如何编写一个导致原始类型的模板?

时间:2015-03-17 14:16:26

标签: c++ templates

我正在编写一个小的定点算术类,其中包含整数和小数位的模板参数。当乘以两个小的固定点类型时,结果应该是更大的固定点类型以捕获完整的结果。例如。将两个8.8定点数相乘得到一个16.16的定点数。

我的班级看起来像这样:

template<typename T, unsigned int bits, unsigned int frac>
class FixedPoint {
  public:
    constexpr FixedPoint(int x = 0) : raw_(x << frac) { }
    constexpr FixedPoint(double x) : raw_(x * (T(1) << frac)) { }
  private:
    T raw_;
}

现在问题是 T 模板参数,特别是对于乘法,因为结果类型与参数类型不同并且不能被推测。写 a * b 不起作用。

我想要做的是将 T 替换为模板类型 Int&lt; bits + frac&gt; ,这是一个int8_t,int16_t,int32_t或int64_t取决于总需要的位数。

我该如何写这样的类型?我把它限制在8,16,32或64位就好了。

3 个答案:

答案 0 :(得分:3)

您可以使用模板和专业化:

template <std::size_t N> struct sizedType;

template <> struct sizedType<8>  { using type = std::uint8_t; };
template <> struct sizedType<16> { using type = std::uint16_t; };
template <> struct sizedType<32> { using type = std::uint32_t; };
template <> struct sizedType<64> { using type = std::uint64_t; };

答案 1 :(得分:2)

这并不仅限于所需的位数。相反,它找到了适合那么多位的最小的一个:

template<class T>struct tag{using type=T;};
template<size_t bits_at_least>
struct int_helper : int_helper<bits_at_least+1> {};

template<> struct int_helper<8  > : tag<int8_t > {};
template<> struct int_helper<16 > : tag<int16_t> {};
template<> struct int_helper<32 > : tag<int32_t> {};
template<> struct int_helper<64 > : tag<int64_t> {};
template<> struct int_helper<128> {}; // unsupported

template<std::size_t bits>
using integer = typename int_helper<bits>::type;

然后integer<3>int8_t

integer<65>integer<128>是一个SFINAE错误(干净整洁),integer<129>是一个错误,会向您发送错误消息(因为它试图实例化无限级联递归模板)。

我们可以通过删除最多63个递归实例并进行位摆弄来更快地编译并生成更好的错误。

template<size_t n>
using size = std::integral_constant<std::size_t, n>;

template<size_t n>
struct bits : size<bits<n/2>{}+1 > {};
template<>
struct bits<0> : size<0> {};

template<class T>struct tag{using type=T;};

template<size_t bits_of_bits>
struct int_helper_2 {};

// optional 0 bits of bits uses char:
template<> struct int_helper_2<0> : tag<int8_t > {};
template<> struct int_helper_2<1> : tag<int8_t > {};
template<> struct int_helper_2<2> : tag<int8_t > {};
template<> struct int_helper_2<3> : tag<int8_t > {};
template<> struct int_helper_2<4> : tag<int16_t> {};
template<> struct int_helper_2<5> : tag<int32_t> {};
template<> struct int_helper_2<6> : tag<int64_t> {};

template<size_t bits_needed>
struct int_helper : int_helper_2< bits<bits_needed>{} > {};

template<size_t bits_needed>
using integer<bits_needed>=typename int_helper<bits_needed>::type;

在所有大小中都提供了很好的SFINAE错误,并且应该编译得更快(更少的类型递归)。

答案 2 :(得分:2)

最简单(也就是最好)是使用别名

template<std::size_t bits>
using integer_with_bits =
  conditional_t<(bits<= 8), std::int8_t,
  conditional_t<(bits<=16), std::int16_t,
  conditional_t<(bits<=32), std::int32_t,
  enable_if_t  <(bits<=64), std::int64_t> > > >;

这是等效于运行时?:?:?:?:级联的编译时间。然后integer_with_bits<3>int8_t,而integer_with_bits<65>(和更大)则会产生编译时错误。在上面我使用了辅助设备

template<bool C, typename T>
using enable_if_t = typename std::enable_if<C,T>::type;

template<bool C, typename T1, typename T2>
using conditional_t = typename std::conditional<C,T1,T2>::type;