试图将两个编译时元组的整数序列相加

时间:2014-10-09 00:23:43

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

如果您要跟踪我的问题历史记录,我会更新维度分析库,以便抛弃宏的噩梦并学习C ++ 11,可变参数模板,元编程和功能编程范式。对于我的生活,这些东西仍然是神奇的。

无论如何,我有一些指数常量元组来定义物理单位。

template<int... I>
using make_dimension = std::tuple<std::ratio<I>...>;

using scalar_dimension = make_dimension<0, 0, 0, 0, 0, 0, 0>;
using length_dimension = make_dimension<1, 0, 0, 0, 0, 0, 0>;
using time_dimension = make_dimension<0, 0, 1, 0, 0, 0, 0>;

这是对SI单位进行建模的库的(部分)。你只能乘以不同的单位,你可以另外添加像单位和标量。这些库是花花公子的,因为如果你不恰当地混合单元,它们会导致编译时错误。有> 400个单位,其中大多数是根据其他单位定义的。乘法单位时,会添加指数,当除以单位时,会减去指数。因此,为了定义速度,我想要一种表达方式:

using velocity_dimension = divide_dimensions<length_dimension, time_dimension>;

这应该在功能上等同于写作:

using velocity_dimension = make_dimension<1, 0, -1, 0, 0, 0, 0>;

我一直在使用谷歌搜索,但我不知道要点击某些命中的术语。我发现的最接近的是一个for_each,它在运行时将一个函数应用于元组的元素......这让我大吃一惊,所以我无法弄清楚如何转向它进入元素的编译时迭代。 &#39; make_dimension&#39;刚刚在上面向我解释过,它让我大吃一惊,但我恢复了。我有点要求提供讲义,所以有没有人有任何好的资源来学习这些东西?我很难相信我是唯一一个对此感兴趣的人。

3 个答案:

答案 0 :(得分:2)

@ dyp在注释中的解决方案使用递归实例化的模板。虽然这是可变参数模板最常用的技术之一,但在这种情况下,递归可能是过度的,因为整个转换集可以在单个包扩展中执行,同时扩展两个参数包:

template<template<class, class> class, class, class>
struct tuple_transform;   // undefined

template<template<class, class> class Transform, class...Ts, class...Vs>
struct tuple_transform<Transform, std::tuple<Ts...>, std::tuple<Vs...>> {
    using type = std::tuple<Transform<Ts, Vs>...>;
};

template<class T, class U>
using divide_dimensions = typename tuple_transform<std::ratio_subtract, T, U>::type;

请注意,上面假设Transform<T, U>是所需结果类型的别名。这符合ratio_add等行为 - 它们是生成的std::ratio的别名模板,因此typename ratio_add<...>::type不是必需的。

Demo

答案 1 :(得分:0)

虽然TC的答案是正确的,你可以简单地使用std::integer_sequence(这是C ++ 14,但可以简单地实现)而不是比率和元组(在我看来)不适合使用constexpr仿函数操纵。 现在你的代码应该如下所示(我没有尝试编译):

template<int... I>
using make_dimension = std::integer_sequence<int, I...>;

template<class Functor, class Dim1, class Dim2>
struct transfrom;

template<class Functor, int... Dims1, int... Dims2>
struct transform<
  Functor, 
  std::integer_sequence<int, Dims1...>, 
  std::integer_sequence<int, Dims2...>
> {
  static_assert(sizeof...(Dims1)==sizeof...(Dims2), "wrong dimensions");
  static constexpr Functor f;
  using type=std::integer_sequence<int, f(Dims1,Dims2)...>;
};

struct add {
  constexpr int operator()(int l, int r) const { return l+r; }
};
struct sub {
  constexpr int operator()(int l, int r) const { return l-r; }
};

template<class T, class U>
using divide_dimensions = typename transform<sub, T, U>::type;

答案 2 :(得分:-1)

我没有足够的信息,但看起来像(1,0,-2,0,0,0,0)就是加速所需要的。 1表示米,-2表示除以秒的平方,就像数学中的负指数一样。