如何专门针对多个整数值范围的 C++ 模板?
How can I specialize a C++ template for multiple ranges of integer values?
我正在尝试创建一个模板 class 来处理比特流。我想在模板中声明一个基础整数类型,该类型将根据模板参数(一个int,位数)。我找到了关于这个主题的两个答案 (How can I specialize a C++ template for a range of integer values? and Integer range based template specialisation) 并实现了以下代码:
template<int BITS>
class MyClass {
typedef typename
std::conditional< BITS <= 8, uint8_t,
std::conditional< BITS <= 16, uint16_t,
std::conditional< BITS <= 32, uint32_t, uint64_t > > >::type
int_type;
...
}
在我的程序中,我实例化了 MyClass<32>
,但是在编译时,我收到以下错误:
no known conversion for argument 1 from ‘uint32_t {aka unsigned int}’ to ‘MyClass<32>::int_type {aka std::conditional<false, short unsigned int, std::conditional<true, unsigned int, long unsigned int> >}’
如果我实例化 MyClass<8>
,一切正常。所以看起来只有std::conditional
的第一层实际上被展开了。
知道如何正确执行此操作吗?
编辑: 我之前没有说明这一点,但我正在寻找一种解决方案,它也适用于任何位大小的实例化(只要它是 64 位的)最多)。所以我希望 MyClass<27>
也能正常工作(选择 uint32_t
)。
越简单越好:
template<unsigned nbits> struct uint {};
template<> struct uint<8> { using type = uint8_t; };
template<> struct uint<16> { using type = uint16_t; };
template<> struct uint<32> { using type = uint32_t; };
template<> struct uint<64> { using type = uint64_t; };
template<int nbits>
struct MyClass { using int_type = typename uint<(nbits/8)*8>::type; };
回答您的编辑并使您的原始代码正常工作。
template<int BITS>
class MyClass {
using int_type =
typename std::conditional< BITS <= 8, uint8_t,
typename std::conditional< BITS <= 16, uint16_t,
typename std::conditional< BITS <= 32, uint32_t, uint64_t >::type >::type >::type;
public:
int_type i;
};
问题的解决方案已经在中提供了。
理解错误信息对我很有启发。
您已将 int_type
定义为:
typedef typename
std::conditional< BITS <= 8, uint8_t,
std::conditional< BITS <= 16, uint16_t,
std::conditional< BITS <= 32, uint32_t, uint64_t > > >::type
int_type;
它在 BITS <= 8
上正常工作,因为
std::conditional< BITS <= 16, uint16_t,
std::conditional< BITS <= 32, uint32_t, uint64_t > >
部分基本上被忽略了。
假设您使用 MyClass<16>
。然后, uint8_t
被忽略。 int_type
是:
std::conditional< BITS <= 16, uint16_t,
std::conditional< BITS <= 32, uint32_t, uint64_t > >
可以简化为:
std::conditional< true, uint16_t,
std::conditional< true, uint32_t, uint64_t > >
不幸的是,这是你不使用 std::conditional<...>::type
得到的类型。
假设您使用 MyClass<32>
。那么 int_type
是:
std::conditional< BITS <= 16, uint16_t,
std::conditional< BITS <= 32, uint32_t, uint64_t > >
可以简化为:
std::conditional< false, uint16_t,
std::conditional< true, uint32_t, uint64_t > >
这就是你得到的类型。
您可以通过打印相应 type_info
对象的名称来了解这些类型。
示例程序:
#include <iostream>
#include <typeinfo>
#include <type_traits>
#include <cstdint>
template<int BITS>
struct MyClass
{
typedef typename
std::conditional< BITS <= 8, uint8_t,
std::conditional< BITS <= 16, uint16_t,
std::conditional< BITS <= 32, uint32_t, uint64_t > > >::type
int_type;
};
int main()
{
typename MyClass<8>::int_type a;
std::cout << typeid(a).name() << std::endl;
typename MyClass<16>::int_type b;
std::cout << typeid(b).name() << std::endl;
typename MyClass<32>::int_type c;
std::cout << typeid(c).name() << std::endl;
typename MyClass<60>::int_type d;
std::cout << typeid(d).name() << std::endl;
}
输出,使用 g++ 5.4.0:
h
St11conditionalILb1EtS_ILb1EjmEE
St11conditionalILb0EtS_ILb1EjmEE
St11conditionalILb0EtS_ILb0EjmEE
您应该看看 Boost.Integer:它的 Integer Type Selection 完全符合您的要求。在您的情况下,您应该使用 boost::uint_t<N>::least
:
#include <boost/integer.hpp>
template<int BITS>
class MyClass {
using int_type = typename boost::uint_t<BITS>::least;
};
我正在尝试创建一个模板 class 来处理比特流。我想在模板中声明一个基础整数类型,该类型将根据模板参数(一个int,位数)。我找到了关于这个主题的两个答案 (How can I specialize a C++ template for a range of integer values? and Integer range based template specialisation) 并实现了以下代码:
template<int BITS>
class MyClass {
typedef typename
std::conditional< BITS <= 8, uint8_t,
std::conditional< BITS <= 16, uint16_t,
std::conditional< BITS <= 32, uint32_t, uint64_t > > >::type
int_type;
...
}
在我的程序中,我实例化了 MyClass<32>
,但是在编译时,我收到以下错误:
no known conversion for argument 1 from ‘uint32_t {aka unsigned int}’ to ‘MyClass<32>::int_type {aka std::conditional<false, short unsigned int, std::conditional<true, unsigned int, long unsigned int> >}’
如果我实例化 MyClass<8>
,一切正常。所以看起来只有std::conditional
的第一层实际上被展开了。
知道如何正确执行此操作吗?
编辑: 我之前没有说明这一点,但我正在寻找一种解决方案,它也适用于任何位大小的实例化(只要它是 64 位的)最多)。所以我希望 MyClass<27>
也能正常工作(选择 uint32_t
)。
越简单越好:
template<unsigned nbits> struct uint {};
template<> struct uint<8> { using type = uint8_t; };
template<> struct uint<16> { using type = uint16_t; };
template<> struct uint<32> { using type = uint32_t; };
template<> struct uint<64> { using type = uint64_t; };
template<int nbits>
struct MyClass { using int_type = typename uint<(nbits/8)*8>::type; };
回答您的编辑并使您的原始代码正常工作。
template<int BITS>
class MyClass {
using int_type =
typename std::conditional< BITS <= 8, uint8_t,
typename std::conditional< BITS <= 16, uint16_t,
typename std::conditional< BITS <= 32, uint32_t, uint64_t >::type >::type >::type;
public:
int_type i;
};
问题的解决方案已经在
理解错误信息对我很有启发。
您已将 int_type
定义为:
typedef typename
std::conditional< BITS <= 8, uint8_t,
std::conditional< BITS <= 16, uint16_t,
std::conditional< BITS <= 32, uint32_t, uint64_t > > >::type
int_type;
它在 BITS <= 8
上正常工作,因为
std::conditional< BITS <= 16, uint16_t,
std::conditional< BITS <= 32, uint32_t, uint64_t > >
部分基本上被忽略了。
假设您使用 MyClass<16>
。然后, uint8_t
被忽略。 int_type
是:
std::conditional< BITS <= 16, uint16_t,
std::conditional< BITS <= 32, uint32_t, uint64_t > >
可以简化为:
std::conditional< true, uint16_t,
std::conditional< true, uint32_t, uint64_t > >
不幸的是,这是你不使用 std::conditional<...>::type
得到的类型。
假设您使用 MyClass<32>
。那么 int_type
是:
std::conditional< BITS <= 16, uint16_t,
std::conditional< BITS <= 32, uint32_t, uint64_t > >
可以简化为:
std::conditional< false, uint16_t,
std::conditional< true, uint32_t, uint64_t > >
这就是你得到的类型。
您可以通过打印相应 type_info
对象的名称来了解这些类型。
示例程序:
#include <iostream>
#include <typeinfo>
#include <type_traits>
#include <cstdint>
template<int BITS>
struct MyClass
{
typedef typename
std::conditional< BITS <= 8, uint8_t,
std::conditional< BITS <= 16, uint16_t,
std::conditional< BITS <= 32, uint32_t, uint64_t > > >::type
int_type;
};
int main()
{
typename MyClass<8>::int_type a;
std::cout << typeid(a).name() << std::endl;
typename MyClass<16>::int_type b;
std::cout << typeid(b).name() << std::endl;
typename MyClass<32>::int_type c;
std::cout << typeid(c).name() << std::endl;
typename MyClass<60>::int_type d;
std::cout << typeid(d).name() << std::endl;
}
输出,使用 g++ 5.4.0:
h
St11conditionalILb1EtS_ILb1EjmEE
St11conditionalILb0EtS_ILb1EjmEE
St11conditionalILb0EtS_ILb0EjmEE
您应该看看 Boost.Integer:它的 Integer Type Selection 完全符合您的要求。在您的情况下,您应该使用 boost::uint_t<N>::least
:
#include <boost/integer.hpp>
template<int BITS>
class MyClass {
using int_type = typename boost::uint_t<BITS>::least;
};