广义混合

时间:2012-02-19 09:07:50

标签: c++ c++11 metaprogramming mixins variadic-templates

我正在写一些代码,我有一个类可以接受mixins作为可变参数模板参数。但是,我还需要mixins才能通过CRTP习惯用法访问基类。这是一个最不能满足我想要的最小例子:

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

但是,我可能传递给Foo的mixin通常会有几个模板参数,如下所示:

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 个答案:

答案 0 :(得分:4)

我不太确定我是否明白这个问题,所以请让我改一下,以便我们能够从正确的方向开始。

在典型的CRTP用例中,您需要将派生类型线程化到基类,同时将其他模板参数传递给各种基类。

也就是说,典型的基类是:

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

您需要创建自己的类型,以便控制XY,同时传递完整的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... {
};

仅仅因为我在模板中如此深入地跋涉已经有一段时间了I checked it worked


当然,Factory本身并不是特定于给定类型的特定类型,因此我们可以重用您尝试过的包装器方法:

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

是的,it works too

答案 1 :(得分:2)

如果我正确理解您的问题,您应该创建模板别名,将每个mixin减少为单个模板参数。

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

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

typedef Foo<BarIntFloat, BazQux> MyFoo;

答案 2 :(得分:0)

这是我提出的解决方案。可能有更优雅的方式来做到这一点,但我想不出任何。需要注意的是,所有使用的mixin都需要首先嵌套在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;
}

答案 3 :(得分:0)

@空隙指针

这是可变参数模板的基本遗漏。用户无法从T ...获得第i个类型,或从值获得第i个值...

以下是来自Andrei Alexandrescu 2012年本土讲座的a link

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

•Ts不是一种类型; vs不是一个值!

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

所以Ts / vs应该是某种元组。