如何为多个整数值范围专门化C++模板?
How can I specialize a C++ template for multiple ranges of integer values?
我正在尝试创建一个用于处理位流的模板类。我想在模板中声明一个底层整数类型,该类型将解析为uint8_t
、uint16_t
、uint32_t
或uint64_t
,具体取决于模板参数(整数、位数)。我找到了关于这个主题的两个答案(如何为一系列整数值专门化C++模板?和基于整数范围的模板专用化)并实现了以下代码:
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;
};
@super的答案中已经提供了该问题的解决方案。
理解错误消息对我很有帮助。
您已将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:它的整数类型选择正是你正在寻找的。在您的情况下,您应该使用boost::uint_t<N>::least
:
#include <boost/integer.hpp>
template<int BITS>
class MyClass {
using int_type = typename boost::uint_t<BITS>::least;
};
- 为什么在全局范围内使用"extern int a"似乎不行?
- 尝试通过多个向量访问变量时,向量下标超出范围
- 错误:未在此范围内声明'reverse'
- 正在将指针转换为范围
- 使用std::transform将一个范围的元素添加到另一个范围中
- 在基于范围的for循环中使用结构化绑定声明
- 如何计算数据类型的范围,例如int
- 是否可以对零模板参数进行模板专门化
- 为什么 const std::p air<K,V>& 在 std::map 上基于范围的 for 循环不起作用?
- 在C++中查找范围的长度
- 如何设置一个范围来提取我想要获得的信息
- 并行用于C++17中数组索引范围内的循环
- 为左值和右值的包装器实现C++范围
- 求出有多少个数字是完美平方,而sqrt()是L,R范围内的素数
- 关于:C++中异常对象的范围:为什么我没有得到副本?
- 超出范围时使用对象
- 如何为多个整数值范围专门化C++模板?
- 如何在类范围内定义/专门化type_trait
- 值范围的模板专门化
- GCC错误:在非命名空间范围内显式专门化