Domanda

Stavo scrivendo del codice in cui ho una classe che può accettare mixin come parametri del modello variadico.Tuttavia, ho anche bisogno che i mixin possano accedere alla classe base tramite l'idioma CRTP.Ecco un esempio minimo che non può fare esattamente quello che voglio:

template <template <class> class... Mixins>
class Foo : Mixins<Foo<Mixins...>>... {};

Comunque un mix a cui potrei passare Foo avrà, in generale, diversi parametri del modello, in questo modo:

template <class Derived, class Type1, class Type2>
class Bar
{
    Derived& operator()()
    {
        return static_cast<Derived&>(*this);
    }
};

Come posso cambiare Foo in modo che possa ereditare da un numero di classi base, dove controllo i parametri del modello accettati da ciascuna classe base?Se passo Foo un elenco di parametri template-template, insieme a un elenco di argomenti da passare loro, quindi non vedo come potrei associare ciascun parametro template-template ai suoi argomenti.Finora avevo pensato a qualcosa del genere, ma non so come procedere.

template <template <class...> class T,
    template <class...> class... Ts>
class Foo : /* How do I retrieve the arguments? */
È stato utile?

Soluzione

Non sono del tutto sicuro di aver compreso il problema, quindi per favore permettetemi di riformularlo in modo da poter iniziare con il piede giusto.

È necessario sottoporre a thread il tipo derivato alle classi base, in un tipico caso d'uso CRTP, passando allo stesso tempo altri parametri del modello alle varie classi base.

Cioè, una tipica classe base sarà:

template <typename Derived, typename X, typename Y>
struct SomeBase {
};

E vuoi creare il tuo tipo in modo da poter controllare il file X E Y e allo stesso tempo passare il completo Derived classe.


Penso che userei il apply trucco per generare al volo la classe base, da un adattatore fornito nell'elenco degli argomenti del file Derived classe.

template <typename Derived, typename X, typename Y>
struct SomeBase {};

template <typename X, typename Y>
struct SomeBaseFactory {
  template <typename Derived>
  struct apply { typedef SomeBase<Derived, X, Y> type; };
};

// Generic application
template <typename Fac, typename Derived>
struct apply {
  typedef typename Fac::template apply<Derived>::type type;
};

Quindi, creerai il tipo come:

typedef MyFoo< SomeBaseFactory<int, float> > SuperFoo;

Dove Foo è definito come:

template <typename... Args>
struct Foo: apply<Args, Foo<Args...>>::type... {
};

E solo perché è passato un po' dall'ultima volta che mi sono immerso così profondamente nei modelli, Ho controllato che funzionasse.


Naturalmente, il Factory in sé non è realmente specifico per un dato tipo, quindi possiamo riutilizzare l'approccio wrapper che hai sperimentato:

template <template <typename...> class M, typename... Args>
struct Factory {
  template <typename Derived>
  struct apply { typedef M<Derived, Args...> type; };
};

E sì, funziona anche.

Altri suggerimenti

Se capisco correttamente la tua domanda, dovresti creare alias di modelli che riducono ogni mixin a un singolo parametro modello.

template <typename Derived>
using BarIntFloat = Bar<Derived, Int, Float>;

template <typename Derived>
using BazQux = Baz<Derived, Qux>;

typedef Foo<BarIntFloat, BazQux> MyFoo;

Ecco una soluzione che mi è venuta in mente. Potrebbe esserci un modo più elegante per farlo, ma non ci potevo pensare. Un avvertimento è che tutti i mixi utilizzati devono prima essere nidificati nel wrapper Struttura, insieme ai rispettivi argomenti.

template <template <class...> class Mixin, class... Args>
struct wrapper
{
        typedef Mixin<Args...> type;
};

template <class... Args>
struct test
{

};

template <class Arg, class... Args>
struct test<Arg, Args...> : Arg::type, test<Args...>
{

};

template <class T>
class mixin1 {};

template <class T1, class T2>
class mixin2 {};

template <class T1, class T2, class T3>
class mixin3 {};

int main()
{
        test<wrapper<mixin1, int>, wrapper<mixin2, int, float>> foo;
        return 0;
}

@void-pointer

Questa è l'omissione di base dei modelli variadici. L'utente non può ottenere il tipo I-th da t ... o ottenere un valore i-th dai valori ...

Qui è un collegamento dalla conferenza nativa 2012 di Andrei Alexandrescu:

template <typename... Ts>
void fun(const Ts&... vs) {}

• TS non è un tipo; vs non è un valore!

typedef Ts MyList; // error!
Ts var; // error!
auto copy = vs; // error!

Quindi TS/VS dovrebbe essere una specie di tupla.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top