【问题标题】:Variadic templates of types, integral constants and template template parameters类型、整数常量和模板模板参数的可变参数模板
【发布时间】:2015-09-13 21:27:26
【问题描述】:

我有以下问题。我有一些类执行输入数组到输出数组的映射。我想要浮点类型,以及数组的长度作为模板参数,所以映射类看起来像这样:

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 类。正如您可能从 cmets 中看到的那样,一层的输出大小等于下一层的输入大小。对于堆栈中的所有映射器,浮点类型只会定义一次。

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

有人对此有想法吗?

【问题讨论】:

  • 如果你对所有东西都使用类型,而不是模板模板参数和非类型模板参数,这会更方便。阅读@Yakk 的元编程答案之一以获取一些示例,例如stackoverflow.com/a/32056973
  • @dyp:感谢您发布该链接,这很好

标签: c++ templates variadic-templates template-meta-programming


【解决方案1】:

这里简单介绍一下基于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&lt;int, 2&gt; 上应用两次square_f 元函数类来计算整数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 自动嵌入派生类中。这种技术称为“元函数转发”,可以减少typename F&lt;T&gt;::type 混乱的数量。

【讨论】:

  • 谢谢,看起来真的很不错。我会试试的。
  • 我成功地部分尝试了您的解决方案。但是后来我收到了更改请求以支持在运行时更改输入/输出大小。因此我不得不重构现在不再使用模板的代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-06-07
  • 1970-01-01
  • 2019-11-22
  • 2016-01-22
  • 2016-12-01
  • 2021-03-08
  • 2021-10-01
相关资源
最近更新 更多