Обобщенные миксины - PullRequest
       29

Обобщенные миксины

3 голосов
/ 19 февраля 2012

Я писал код, в котором у меня есть класс, который может принимать миксины в качестве параметров шаблона переменной. Однако мне также нужны миксины, чтобы иметь доступ к базовому классу через идиому CRTP. Вот минимальный пример, который не может сделать то, что я хочу:

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

Однако миксин, который я мог бы передать Foo, в общем случае будет иметь несколько параметров шаблона, например:

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

Как я могу изменить Foo, чтобы он мог наследоваться от ряда базовых классов, где я контролирую параметры шаблона, принятые каждым базовым классом? Если я вручу Foo список параметров шаблона-шаблона вместе со списком аргументов для передачи им, то я не вижу, как я смогу связать каждый параметр шаблона-шаблона с его аргументами. До сих пор я думал о чем-то подобном, но я не знаю, как мне поступить.

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

Ответы [ 4 ]

4 голосов
/ 19 февраля 2012

Я не совсем уверен, что понял проблему, поэтому позвольте мне перефразировать ее, чтобы мы могли начать с правой ноги.

Вам необходимо связать производный тип с базовыми классами, в типичном случае использования CRTP, и в то же время передать другой параметр шаблона различным базовым классам.

То есть типичный базовый класс будет:

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

И вам нужно создать свой тип, чтобы вы могли контролировать X и Y и одновременно проходить полный класс Derived.


Думаю, я бы использовал трюк apply для генерации базового класса на лету из адаптера, предоставленного в списке аргументов класса Derived.

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

Затем вы должны создать тип как:

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

Где Foo определяется как:

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

И только из-за того, что я долго так тщательно разбирался в шаблонах, Я проверил, как это работает .


Конечно, Factory сам по себе не является специфическим для данного типа, поэтому мы можем использовать подход оболочки, который вы экспериментировали:

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

И да, тоже работает .

2 голосов
/ 19 февраля 2012

Если я правильно понимаю ваш вопрос, вы должны создать псевдонимы шаблона, которые сводят каждый миксин к одному параметру шаблона.

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

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

typedef Foo<BarIntFloat, BazQux> MyFoo;
0 голосов
/ 19 февраля 2012

@ аннулируются-указатель

Это основное упущение вариационных шаблонов. Пользователь не может получить i-тый тип из T ... или получить i-тое значение из значений ...

Вот ссылка с лекции 2012 года Андрея Александреску:

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

• Ц не тип; vs не является значением!

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

Так что Ts / vs должен быть своего рода кортежем.

0 голосов
/ 19 февраля 2012

Вот решение, которое я придумал.Возможно, есть более элегантный способ сделать это, но я не мог придумать ни одного.Одно предупреждение: все используемые миксины должны быть сначала вложены в структуру wrapper вместе с соответствующими аргументами.

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