compilare cicli temporali

compilare cicli temporali

No, non è direttamente possibile. La metaprogrammazione dei modelli è un puro linguaggio funzionale. Ogni valore o tipo definito attraverso di esso è immutabile . Un ciclo richiede intrinsecamente variabili mutabili (verifica ripetutamente alcune condizioni finché non si verifica X , quindi esci dal ciclo).

Invece, in genere faresti affidamento sulla ricorsione. (Crea un'istanza di questo modello con un parametro di modello diverso ogni volta, finché non raggiungi una condizione di terminazione).

Tuttavia, ciò può risolvere tutti gli stessi problemi di un ciclo.

Modifica:ecco un rapido esempio, calcolando il fattoriale di N usando la ricorsione in fase di compilazione:

template <int N>
struct fac {
  enum { value = N * fac<N-1>::value };
};

template <>
struct fac<0> {
  enum { value = 1 };
};

int main() {
  assert(fac<4>::value == 24);
}

La metaprogrammazione dei modelli in C++ è un linguaggio completo di Turing, quindi finché non ti imbatti in vari limiti interni del compilatore, puoi risolvere praticamente qualsiasi problema con esso.

Tuttavia, per scopi pratici, potrebbe valere la pena esaminare librerie come Boost.MPL, che contiene un gran numero di strutture di dati e algoritmi che semplificano molte attività di metaprogrammazione.


Sì. Possibile usando ricorsività del tempo di compilazione .

Stavo provando con il tuo codice ma poiché non era compilabile ecco un esempio modificato e di compilazione:

template<class C, int T=10>
class CountSketch
{
  template<int N>
  void Init ()
  {
    Init<N-1>();
    hashfuncs[N] = &CountSketch<C>::template hash<N>;
    cout<<"Initializing "<<N<<"th element\n";
  }

public:
    CountSketch()
    {
      Init<T>();
    }
private:
   template<int offset>
   size_t hash(C &c)
   {
     return 0;
   }
   size_t (CountSketch::*hashfuncs[T])(C &c);
};

template<>
template<>
void CountSketch<int,10>::Init<0> ()
{
  hashfuncs[0] = &CountSketch<int,10>::hash<0>;
  cout<<"Initializing "<<0<<"th element\n";
}

Demo. L'unico vincolo di questa soluzione è che devi fornire la versione specializzata finale come CountSketch<int,10>::Init<0> per qualsiasi tipo e dimensione.


Hai bisogno di una combinazione di boost::mpl::for_each e boost::mpl::range_c.

Nota:questo risulterà in codice di runtime e questo è ciò di cui hai effettivamente bisogno. Perché non c'è modo di conoscere il risultato di operator& al momento della compilazione. Almeno nessuno di cui sono a conoscenza.

La vera difficoltà con questo è costruire una struttura basata su modelli su un parametro int (mpl::int_ nel nostro caso) e che esegue l'assegnazione quando operator() viene chiamato e abbiamo anche bisogno di un functor per catturare effettivamente il puntatore this.

È un po' più complicato di quanto mi aspettassi, ma è divertente.

#include <boost/mpl/range_c.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/mpl/copy.hpp>

// aforementioned struct
template<class C, class I>
struct assign_hash;

// this actually evaluates the functor and captures the this pointer
// T is the argument for the functor U
template<typename T>
struct my_apply {
  T* t;
  template<typename U>
  void operator()(U u) {
    u(t);
  }
};

template<class C, int T=10, int B=10>
class CountSketch
{
public:
  CountSketch()
    {   
      using namespace boost::mpl;

      // we need to do this because range_c is not an ExtensibleSequence
      typedef typename copy< range_c<int, 0, T>,
                             back_inserter< vector<> > >::type r;
      // fiddle together a vector of the correct types
      typedef typename transform<r, typename lambda< assign_hash<C, _1 > >::type >
        ::type assignees;

      // now we need to unfold the type list into a run-time construct
      // capture this
      my_apply< CountSketch<C, T, B> > apply = { this };
      // this is a compile-time loop which actually does something at run-time
      for_each<assignees>(apply);
    };

  // no way around
  template<typename TT, typename I>
  friend struct assign_hash;

private:
  template<int offset>
  size_t hash(C& c)
    {
      return c;
      // return (reinterpret_cast<int>(&c)+offset)%B;
    }
  size_t (CountSketch::*hashfuncs[T])(C &c);
};

// mpl uses int_ so we don't use a non-type template parameter 
// but get a compile time value through the value member
template<class C, class I>
struct assign_hash {
  template<typename T>
  void operator()(T* t) {
    t->hashfuncs[I::value] = &CountSketch<C>::template hash<I::value>;
  }
};

int main() 
{
  CountSketch<int> a;
}