Question

J'écrivais un code où j'ai une classe qui peut accepter mixins comme paramètres de modèle variadique. Cependant, je dois aussi mixins pour pouvoir accéder à la classe de base à travers l'idiome CRTP. Voici un exemple minimal qui ne peut pas tout à fait ce que je veux:

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

Cependant, un mixin que je pourrais passer à Foo sera, en général, ont plusieurs paramètres de modèle, comme ceci:

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

Comment puis-je changer Foo pour que je puisse avoir hérité d'un certain nombre de classes de base, où je contrôle les paramètres du modèle accepté par chaque classe de base? Si la main que je Foo une liste de paramètres modèle-modèle, ainsi qu'une liste d'arguments pour passer à eux, alors je ne vois pas comment je serais en mesure d'associer chaque paramètre modèle-modèle avec ses arguments. Jusqu'à présent, je pensais à quelque chose comme ça, mais je ne sais pas comment je procéderais.

template <template <class...> class T,
    template <class...> class... Ts>
class Foo : /* How do I retrieve the arguments? */
Était-ce utile?

La solution

I am not quite sure I understood the problem, so please let me rephrase it so that we can start on the right foot.

You need to thread the derived type to the base classes, in a typical CRTP use case, while at the same time passing other template parameter to the various base classes.

That is, a typical base class will be:

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

And you want need to create your type so that you can control the X and Y and at the same time pass the complete Derived class.


I think I would use the apply trick to generate the base class on the fly, from an adapter provided in the argument list of the Derived class.

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;
};

Then, you would create the type as:

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

Where Foo is defined as:

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

And just because it's been a while since I trudged so deeply in templates, I checked it worked.


Of course, the Factory itself is not really a specific to a given type, so we can reuse the wrapper approach you had experimented:

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

And yes, it works too.

Autres conseils

If I understand your question correctly, you should create template aliases that reduce each mixin to a single template parameter.

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

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

typedef Foo<BarIntFloat, BazQux> MyFoo;

Here's a solution I came up with. There may be a more elegant way to do this, but I couldn't think of any. One caveat is that all of the mixins used need to first be nested in the wrapper struct, along with their respective arguments.

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

This is basic omission of variadic templates. User cannot get i-th type from T... or get i-th value from values...

Here is a link from going native 2012 lecture by Andrei Alexandrescu:

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

• Ts is not a type; vs is not a value!

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

So Ts/vs should be some kind of tuple.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top