Общие микшины
-
27-10-2019 - |
Вопрос
Я писал какой -то код, где у меня есть класс, который может принять микшины в качестве параметров переменного шаблона. Тем не менее, мне также нужно, чтобы микшины могли получить доступ к базовому классу через идиому 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? */
Решение
Я не совсем уверен, что понял проблему, поэтому, пожалуйста, позвольте мне перефразировать ее, чтобы мы могли начать правую ногу.
Вам необходимо пропустить производный тип на базовые классы, в типичном варианте использования 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; };
};
И да, Это тоже работает.
Другие советы
Если я правильно понимаю ваш вопрос, вы должны создать псевдонимы шаблонов, которые уменьшают каждый миксин до одного параметра шаблона.
template <typename Derived>
using BarIntFloat = Bar<Derived, Int, Float>;
template <typename Derived>
using BazQux = Baz<Derived, Qux>;
typedef Foo<BarIntFloat, BazQux> MyFoo;
Вот решение, которое я придумал. Там может быть более элегантный способ сделать это, но я не мог придумать ничего. Одно предостережение заключается в том, что все используемые микшины должны сначала быть вложенными в 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;
}
@void-pointer
Это основное упущение вариальных шаблонов. Пользователь не может получить i-th-тип от T ... или получить I-три значения от значений ...
Вот ссылка от «Находной лекции 2012» Андрея Александреску:
template <typename... Ts>
void fun(const Ts&... vs) {}
• TS не является типом; VS не ценность!
typedef Ts MyList; // error!
Ts var; // error!
auto copy = vs; // error!
Таким образом, TS/VS должен быть каким -то кортежом.