문제

I was writing some code where I have a class that can accept mixins as variadic template parameters. However, I also need the mixins to be able to access the base class through the CRTP idiom. Here's a minimal example that cannot quite do what I want:

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

However, a mixin that I might pass to Foo will, in general, have several template parameters, like so:

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

How can I change Foo so that I can have it inherit from a number of base classes, where I control the template parameters accepted by each base class? If I hand Foo a list of template-template parameters, along with a list of arguments to pass to them, then I don't see how I would be able to associate each template-template parameter with its arguments. So far, I thought of something like this, but I don't know how I would proceed.

template <template <class...> class T,
    template <class...> class... Ts>
class Foo : /* How do I retrieve the arguments? */
도움이 되었습니까?

해결책

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.

다른 팁

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.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top