将类似数组的对象作为模板值参数

时间:2016-12-03 10:09:31

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

我想实现一个

template<class ValueType,UnitTag x>
clsas Quantity;

使用像

这样的运营商
template<UnitTag y>
Quantity<T,x+y> operator*(Quantity<T,y> b)
    {return Quantity<T,x+y>(m_value*b.value());}

(也可以添加数量,但只能添加相同种类)

UnitTag上的操作必须以元素方式完成

x_0 + y_0 = z_0
x_1 + y_1 = z_1
x_2 + y_2 = z_2
x_3 + y_3 = z_3
...

最直接的方法是让UnitTag成为constexpr数组。但这不能用作模板参数。作为一种解决方法,我可以使用大整数类型,并使用少量位来表示每个维度。然而,这给出了尺寸数量或每个尺寸的功率的限制:例如,对于64位和16维度,我仅覆盖[L ^( - 8),L ^ 7]。这应该对大多数应用程序都有好处,但是这个类不能处理激进分子,因为这需要分数幂。

有没有办法在模板参数中传递超过64位的信息?例如,是否可以对模板参数包进行逐元素操作?所需的元素操作是:

  • 添加(用于乘法)
  • 减法(用于划分)

对于激进派:

  • 分区(这要求元素的行为类似于有理数。可以使用constexpr word()访问器实现为类)

2 个答案:

答案 0 :(得分:3)

我尝试根据

提出解决方案
  

是否可以对模板参数包进行逐元素操作?

不确定(我不知道你对这个值究竟想做什么)但是如果你将模板参数包包装在std::integer_sequence(或std::index_sequence中,如果你可以使用一包std::size_t),对我来说似乎是可能的。

不幸的是,std::integer_sequencestd::index_sequence是C ++ 14的功能。但是如果你需要在C ++ 11中,很容易实现类似的东西。

以下是使用std::index_sequence

的示例

- 编辑 - 修改示例添加减法/除法

#include <utility>
#include <type_traits>

template <typename, typename>
struct addVI;

template <std::size_t ... Is, std::size_t ... Js>
struct addVI<std::index_sequence<Is...>, std::index_sequence<Js...>>
 {
   static_assert(sizeof...(Is) == sizeof...(Js), "! add");

   using type = std::index_sequence<(Is+Js)...>;
 };

template <typename, typename>
struct subVI;

template <std::size_t ... Is, std::size_t ... Js>
struct subVI<std::index_sequence<Is...>, std::index_sequence<Js...>>
 {
   static_assert(sizeof...(Is) == sizeof...(Js), "! sub");

   using type = std::index_sequence<(Is-Js)...>;
 };

template <typename, typename>
struct foo;

template <typename T, std::size_t ... Is>
struct foo<T, std::index_sequence<Is...>>
 {
   template <std::size_t ... Js>
   using Ks = typename addVI<std::index_sequence<Is...>,
                             std::index_sequence<Js...>>::type;

   template <std::size_t ... Js>
   using Ls = typename subVI<std::index_sequence<Is...>,
                             std::index_sequence<Js...>>::type;

   template <std::size_t ... Js>
   foo<T, Ks<Js...>> operator* (foo<T, std::index_sequence<Js...>> const & b)
    { return foo<T, Ks<Js...>>(); }

   template <std::size_t ... Js>
   foo<T, Ls<Js...>> operator/ (foo<T, std::index_sequence<Js...>> const & b)
    { return foo<T, Ls<Js...>>(); }

 };

int main ()
 {
   foo<int, std::index_sequence<1, 2, 3>> f1;
   foo<int, std::index_sequence<2, 3, 5>> f2;

   static_assert(std::is_same<decltype(f1*f2),
                              foo<int, std::index_sequence<3, 5, 8>>>::value,
                 "!!");

   static_assert(std::is_same<decltype(f2/f1),
                              foo<int, std::index_sequence<1, 1, 2>>>::value,
                 "!!!");
 }

答案 1 :(得分:0)

只需传递几个整数参数。

作为替代方案,请查看本书&#34; C ++模板元编程&#34;亚伯拉罕和古尔托沃伊。他们将这个想法命名为&#34;维度分析&#34;并使用UnitTag的类型列表。

typedef mpl::vector_c<int,0,1,0,0,0,0,0> length;
typedef mpl::vector_c<int,0,0,1,0,0,0,0> si_time;
...
typedef mpl::vector_c<int,0,1,-1,0,0,0,0> velocity;
...

标记D1D2的乘法运算符生成类型列表

typename mpl::transform<D1,D2,mpl::plus<_1,_2> >::type