如何编写生成原始类型的模板?
How to write a template resulting in a primitive type?
我正在编写一个带有整数和小数位模板参数的小定点算法 class。当将两个小的定点类型相乘时,结果应该是一个更大的定点类型以捕获完整的结果。例如。两个 8.8 定点数相乘得到 16.16 定点数。
我的 class 看起来像这样:
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 不起作用。
我想做的是用模板类型 Int 替换 T int8_t、int16_t、int32_t 或 int64_t 取决于所需的总位数。
这样的类型怎么写?我可以将其限制为 8、16、32 或 64 位。
您可以使用模板和专业化:
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; };
这并没有将其完全限制为所需的位数。相反,它会找到适合那么多位的最小位:
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 错误,并且应该编译得更快(更少的类型递归)。
最简单(也是最好)的方法是使用别名
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;
我正在编写一个带有整数和小数位模板参数的小定点算法 class。当将两个小的定点类型相乘时,结果应该是一个更大的定点类型以捕获完整的结果。例如。两个 8.8 定点数相乘得到 16.16 定点数。
我的 class 看起来像这样:
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 不起作用。
我想做的是用模板类型 Int
这样的类型怎么写?我可以将其限制为 8、16、32 或 64 位。
您可以使用模板和专业化:
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; };
这并没有将其完全限制为所需的位数。相反,它会找到适合那么多位的最小位:
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 错误,并且应该编译得更快(更少的类型递归)。
最简单(也是最好)的方法是使用别名
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;