根据模板整数参数选择一个整数类型
Select an integer type based on template integer parameter
我想创建一个类模板,它接受一个无符号整数参数,并具有一个成员u_
,其类型是将保存该整数参数的最小无符号整数类型。
因此:
template <uint64_t k>
class A {
??? u_;
};
对于A<0>
,u_
的类型应为uint8_t
。与A<255>
相同。对于A<256>
,u_
应为uint16_t
等类型。
你将如何实现这一点?
这段元编程技巧实现了它:
template<unsigned int Y> struct typed
{
typedef typename typed<(Y & (Y - 1)) == 0 ? Y / 2 : (Y & (Y - 1))>::type type;
};
template<> struct typed<0>
{
typedef std::uint8_t type;
};
template<> struct typed<256>
{
typedef std::uint16_t type;
};
template<> struct typed<65536>
{
typedef std::uint32_t type;
};
/* ToDo - add more specialisations as necessary*/
template<unsigned k> class A
{
public:
unsigned static const k_ = k; /*constexpr if your compiler supports it*/
typename typed<k>::type u_;
};
用法正是问题所在。
非专用模板版本采用以前的类型。typed<0>
阻止静态递归。其他专业是适当类型的锚定点。
编译时可评估的(Y & (Y - 1)) == 0 ? Y / 2 : (Y & (Y - 1))
通过移除Y
的最右边位直到达到2的幂,然后随后除以2来减少实例化的数量。(确认@Jarod42(。
使用C++11,您可以使用std::conditional:
#include <cassert>
#include <cstdint>
#include <limits>
#include <type_traits>
template<std::uint32_t K>
class A
{
public:
decltype(K) k_ = K;
typename std::conditional<K <= UINT8_MAX,
std::uint8_t,
typename std::conditional<K <= UINT16_MAX,
std::uint16_t,
std::uint32_t>::type>::type u_;
};
int main()
{
A<100> small;
A<1000> medium;
A<100000> large;
assert( (std::is_same<std::uint8_t, decltype(small.u_)>::value) );
assert( (std::is_same<std::uint16_t, decltype(medium.u_)>::value) );
assert( (std::is_same<std::uint32_t, decltype(large.u_)>::value) );
}
这假设:
template<uint8_t k, typename >
中的uint8_t
只是一个疏忽,或者,正如Aaron McDaid的评论所指出的,该示例不起作用。我将uint8_t
更改为uint32_t
(示例可以平滑地扩展为uint64_t
(int k_ = k;
是类内成员初始化。对于常量定义,可以使用enum {k_ = K};
- CCD_ 20中的CCD_ 19是数据成员。如果是类型定义,则可以使用
typedef
或类型别名(C++11(轻松更改示例
如果你不能使用C++11,有boost::conditional,或者你可以编写自己的版本:
template<bool, class T, class F>
struct conditional { typedef T type; };
template<class T, class F>
struct conditional<false, T, F> { typedef F type; };
如果我们想要的是:给定一个uint64_t
模板参数,给定能够表示它的最小无符号类型,那么我们真正想要的只是编译时的简单迭代。
namespace details {
template <typename T>
struct tag {
using type = T;
};
// base case: just fail
template <uint64_t V, typename... >
struct min_unsigned_type;
// recursive case: check using numeric_limits
template <uint64_t V, typename T, typename... Ts>
struct min_unsigned_type<V, T, Ts...>
: std::conditional_t<(V <= std::numeric_limits<T>::max()),
tag<T>,
min_unsigned_type<V, Ts...>>
{ };
}
然后只是一个别名来把事情包装在一起:
template <uint64_t V>
using min_unsigned_type =
typename details::min_unsigned_type<V,
uint8_t, uint16_t, uint32_t, uint64_t>::type;
这还有一个额外的优势,可以轻松地指定要走多远,甚至可以添加更大的无符号类型(如果你觉得有必要的话(。
最后是你的课程:
template <uint64_t V>
struct A {
static constexpr uint64_t k_ = V;
min_unsigned_type<V> u_;
};
template<uintmax_t Id>
struct A;
template<>
struct A<0>{
enum {id = 0};
using type = uint8_t;
};
template<>
struct A<255>{
enum {id = 255};
using type = uint8_t;
};
template<>
struct A<256>{
enum {id = 256};
using type = uint16_t;
};
int main(){
typename A<255>::type a0 = 255; // uint8_t
typename A<256>::type a1 = 256; // uint16_t
}
但我认为你想有一个类,这样256下的每个值都会定义uint8_t
,65536下的每一个值都会限定uint16_t
等等。
所以以防万一,你会这样做:
template<uintmax_t Value>
struct A{
enum {value = Value};
using type = std::conditional_t<
(Value <= std::numeric_limits<uint8_t>::max()), uint8_t,
std::conditional_t<
(Value <= std::numeric_limits<uint16_t>::max()), uint16_t,
std::conditional_t<
(Value <= std::numeric_limits<uint32_t>::max()), uint32_t
std::conditional_t<
(Value <= std::numeric_limits<uint64_t>::max()), uint64_t, uintmax_t
>
>
>
>;
};
下面是的一个实例
您可以使用部分绑定模板的声明:
template<uint8_t k>
using A_uint8 = A<k, uint8_t>;
template<uint8_t k>
using A_uint16 = A<k, uint16_t>;
然后:
A_uint8<7> hello; // -> A<7, uint8_t>;
A_uint16<256> hello; // -> A<256, uint16_t>;
非常感谢。你们太棒了!顺便说一下,我使用的是:
typedef typename std::conditional<k <= UINT8_MAX,
std::uint8_t,
typename std::conditional<k <= UINT16_MAX,
std::uint16_t,
typename std::conditional<k <= UINT32_MAX,
std::uint32_t,
std::uint64_t>::type>::type>::type TypeU;
std::pair<TypeU, std::shared_ptr<ProtoData>> min_;
std::pair<TypeU, std::shared_ptr<ProtoData>> max_;
相关文章:
- 整数类型应该显式转换(例如"int"到"无符号")还是只会增加混乱?
- 涉及旧式枚举和整数类型的重载解析
- 将字符串转换为整数类型T,检查是否存在溢出
- 整数文本太大,无法用任何整数类型表示--C++
- isdigit(c) - 字符或整数类型?
- 为什么对小于 4 个字节的整数类型的位操作会发生意外行为?
- C++模板专用化 - 将其他整数类型委托给uint64_t
- 何时应使用 C++ 固定宽度整数类型,它们如何影响性能?
- 根据浮点数选择最小整数类型
- 为什么 QVariant 将字符类型视为整数类型
- 我们可以在整数类型的双指针中分配2D整数数组的地址吗?怎么可能
- 默认情况下,决定整数类型是唱歌或无符号的类型
- 是否可以根据类型是整数类型还是浮点类型重载模板函数
- 使用固定整数类型的安全性
- 如何使用条件来检查类型名 T 是否是 C++ 中浮点类型的整数类型
- C++文本整数类型
- 哪种整数类型可以安全且便携式用于始终保持指针值
- 检测整数类型变量上的空白输入
- 为什么对Chrono :: Nanseconds的表示类型是签名的整数类型
- 如何处理警告:从较小的整数类型int转换为int*