类型的可变参数模板、整型常量和模板模板参数
Variadic templates of types, integral constants and template template parameters
我遇到了以下问题。我有一些 classes 执行输入数组到输出数组的映射。我想要 float 类型,以及数组的长度作为模板参数,所以映射 classes 看起来像这样:
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>
{};
到目前为止一切顺利。我的目标是编写一个 class 来堆叠这些 Mapper classes 的不同实例。我希望能够编写这样的代码:
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
class 应该将映射器实例存储在 std::tuple
中。我希望元组具有以下类型:
std::tuple<
FirstMapper<double, input_1, input_2>,
SecondMapper<double, input_2, input_3>,
FirstMapper<double, input_3, output>
// ...
>;
如省略号所示,我想添加任意数量的 Mapper classes。正如您可能从评论中看到的那样,一层的输出大小等于下一层的输入大小。 float 类型将只为堆栈中的所有映射器定义一次。
有人有想法吗?我已经看到 问题,它解决了交替类型(整型常量和类型)问题,但是它似乎不适用于模板模板参数,因为我总是得到像 expected a type, got 'FirstMapper'
这样的错误。
有人对此有想法吗?
这里简单介绍一下基于Boost.MPL的模板元编程。实质是对所有内容都使用 classes,以便在您的代码中获得尽可能多的规律性。
首先,使用integral_constant
来包装常量。这称为 "metadata",该值作为嵌套数据成员包含在 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;
};
您可以使用 classes,包括整数常量元数据,作为 "metafunctions" 的参数:常规 class 模板 return 它们的值作为称为 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)>
{};
为了在传递元函数时避免模板-模板参数,您使用元函数 classes:这些是包含嵌套元函数 apply
[=26] 的常规 classes =]
// higher-order metafunction: class that has nested metafunction "apply" which returns square
struct square_f
{
template<class X>
struct apply
:
square<X>
{};
};
要了解上述定义的有用性,通过在上两次应用 square_f
元函数 class 来计算整数 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, "");
}
要将其推广到可变模板参数,只需使用
template<class... Xs>
struct some_fun;
对于采用可变数量参数的元函数。这留作练习。要点是通过合适的包装器将每个 (data, class, function) 参数统一视为 class。
注意:我使用继承自动将嵌套的type
嵌入派生的classes。这种技术称为 "metafunction forwarding" 并减少了 typename F<T>::type
混乱的数量。
我遇到了以下问题。我有一些 classes 执行输入数组到输出数组的映射。我想要 float 类型,以及数组的长度作为模板参数,所以映射 classes 看起来像这样:
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>
{};
到目前为止一切顺利。我的目标是编写一个 class 来堆叠这些 Mapper classes 的不同实例。我希望能够编写这样的代码:
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
class 应该将映射器实例存储在 std::tuple
中。我希望元组具有以下类型:
std::tuple<
FirstMapper<double, input_1, input_2>,
SecondMapper<double, input_2, input_3>,
FirstMapper<double, input_3, output>
// ...
>;
如省略号所示,我想添加任意数量的 Mapper classes。正如您可能从评论中看到的那样,一层的输出大小等于下一层的输入大小。 float 类型将只为堆栈中的所有映射器定义一次。
有人有想法吗?我已经看到 expected a type, got 'FirstMapper'
这样的错误。
有人对此有想法吗?
这里简单介绍一下基于Boost.MPL的模板元编程。实质是对所有内容都使用 classes,以便在您的代码中获得尽可能多的规律性。
首先,使用integral_constant
来包装常量。这称为 "metadata",该值作为嵌套数据成员包含在 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;
};
您可以使用 classes,包括整数常量元数据,作为 "metafunctions" 的参数:常规 class 模板 return 它们的值作为称为 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)>
{};
为了在传递元函数时避免模板-模板参数,您使用元函数 classes:这些是包含嵌套元函数 apply
[=26] 的常规 classes =]
// higher-order metafunction: class that has nested metafunction "apply" which returns square
struct square_f
{
template<class X>
struct apply
:
square<X>
{};
};
要了解上述定义的有用性,通过在上两次应用 square_f
元函数 class 来计算整数 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, "");
}
要将其推广到可变模板参数,只需使用
template<class... Xs>
struct some_fun;
对于采用可变数量参数的元函数。这留作练习。要点是通过合适的包装器将每个 (data, class, function) 参数统一视为 class。
注意:我使用继承自动将嵌套的type
嵌入派生的classes。这种技术称为 "metafunction forwarding" 并减少了 typename F<T>::type
混乱的数量。