2

我遇到以下问题。我有一些类将输入数组映射到输出数组。我想有float类型,以及阵列作为模板参数的长度,所以映射类是这样的:类型,积分常量和模板模板参数的变量模板

template <typename FloatType, std::size_t input, std::size_t output> 
class Mapper 
{}; 

template <typename FloatType, std::size_t input, std::size_t output> 
class FirstMapper : public Mapper<FloatType, input, output> 
{}; 

template <typename FloatType, std::size_t input, std::size_t output> 
class SecondMapper : public Mapper<FloatType, input, output> 
{}; 

到目前为止好。我的目标是编写一个堆叠这些Mapper类的不同实例的类。我希望能写出这样的代码:

StackedMapper< 
       double,  // the FloatType, obviously 
       input_1,  // the size of the first mapper's input array 
       FirstMapper, // the template template type of the first mapper 
       input_2,  // the size of the first mapper's output and 
          // second mapper's input array 
       SecondMapper, // the template template type of the second mapper 
       input_3,  // the size of the second mapper's output and 
          // third mapper's input array 
       FirstMapper, // the template template type of the third mapper 
       output  // the size of the third mapper's output array 
       // ... any additional number of Mapper classes plus output sizes 
      > stacked_mapper; 

内部,StackedMapper类应该映射器实例存储在std::tuple。我期望元组有以下类型:

std::tuple< 
      FirstMapper<double, input_1, input_2>, 
      SecondMapper<double, input_2, input_3>, 
      FirstMapper<double, input_3, output> 
      // ... 
      >; 

如省略号所示,我想添加任意数量的Mapper类。正如您从注释中看到的那样,一个图层的输出大小等于下一个图层的输入大小。对于堆栈中的所有映射器,浮点类型只能定义一次。

有没有人有想法?我见过this问题,它解决了交替类型(积分常量和类型)问题,但它似乎不适用于模板模板参数,因为我总是遇到类似expected a type, got 'FirstMapper'的错误。

有没有人有这个想法?

+3

如果您对所有内容使用类型,而不是模板模板参数和非类型模板参数,则更方便。阅读@ Yakk元编程答案中的一个例子,例如http://stackoverflow.com/a/32056973/ – dyp

+0

@dyp:感谢发布该链接,这是一个好的 –

回答

2

下面是简要介绍了模板元编程基于Boost.MPL。其实质是为所有事情使用类,以便尽可能多地获得代码中的规律性。

首先,使用integral_constant来包装常量。这被称为“元数据”,并且该值被包含为嵌套数据成员value

// nullary metafunction ("metadata"), wrap "value" 
template<class T, T v> 
struct integral_constant 
{ 
    using type = integral_constant<T, v>; 
    using value_type = T; 
    static constexpr auto value = v; 
}; 

您可以使用类,包括整型常量的元数据,作为参数传递给“元函数”:返回自己的价值作为一个叫做type嵌套型普通类模板。

// regular metafunction: class template that takes metadata "X", returns "type" with "value" squared 
template<class X> 
struct square 
: 
    integral_constant<typename X::value_type, (X::value * X::value)> 
{}; 

为了避免模板,模板参数围绕元功能路过的时候,可以使用元函数类:一类是包含嵌套元函数普通班apply

// higher-order metafunction: class that has nested metafunction "apply" which returns square 
struct square_f 
{ 
    template<class X> 
    struct apply 
    : 
     square<X> 
    {}; 
}; 

要看到上面定义的有用性,通过在integral_constant<int, 2>上应用square_f元函数类两次来计算整数2的平方和四次方是非常简单的,其中integral_constant<int, 2>

// regular metafunction that takes higher-order metafunction "F" and metafunction "X" and returns "F<F<X>>" 
template<class F, class X> 
struct apply_twice 
: 
    F::template apply<typename F::template apply<X>::type> 
{}; 

template<class X> 
struct quartic 
: 
    apply_twice<square_f, X> 
{}; 

int main() 
{ 
    using two = integral_constant<int, 2>; 
    static_assert(4 == square<two>::value, "");   
    static_assert(16 == quartic<two>::value, ""); 
} 

Live Example

它推广为可变参数模板参数,只需要使用

template<class... Xs> 
struct some_fun; 

于拍摄参数的可变参数数量元函数。这留作练习。主要观点是通过合适的包装将每个(数据,类,函数)参数统一视为一个类。

注意:我使用继承来自动嵌入派生类中嵌套type。这种技术被称为“元功能转发”,并减少了杂乱的数量。

+0

谢谢,看起来真不错。我会尝试的。 –

+0

我部分地尝试了成功的解决方案。但后来我得到了更改请求,以支持在运行时更改输入/输出大小。因此,我不得不重构现在不再使用模板的代码。 –

相关问题