在编译时确定整型中的位数
Determine number of bits in integral type at compile time
注意:我在诸如"msg(long("之类的函数的模糊重载中添加了一个类似但大大简化的问题版本,候选函数为"msg(int32_t("和"msg(int64_t("。该版本的优点是在单个文件中具有完整的可编译示例。
问题
我有一个 C 库,其功能如下
obj_from_int32(int32_t& i);
obj_from_int64(int64_t& i);
obj_from_uint32(uint32_t& i);
obj_from_uint64(uint64_t& i);
在这种情况下,int32_t
等类型不是std
的类型 - 它们是实现定义的,在本例中是一个字符数组(在下面的示例中,我省略了转换 - 它不会改变关于根据整型中的位数将 intergral 类型映射到特定函数的问题(。
我有第二个C++接口类,它有这样的构造函数
MyClass(int z);
MyClass(long z);
MyClass(long long z);
MyClass(unsigned int z);
MyClass(unsigned long z);
MyClass(unsigned long long z);
请注意,我不能用std::int32_t
样式类型替换此界面 - 如果可以的话,我不需要问这个问题;)
问题是如何根据整型中的位数调用正确的obj_from_
函数。
建议的解决方案
我提出了两个建议的解决方案,因为没有杀手级解决方案浮到列表的顶部,并且有一些是破碎的。
解决方案 1
由干杯和hth提供。从这一点开始的评论是我自己的 - 随时评论和/或编辑。
优势 - 相当简单(至少与boost::enable_if
相比( - 不依赖第三方库(只要编译器支持tr1
(
*弊** - 如果需要更多函数(如anotherObj_from_int32
等(,则需要更多代码
这个解决方案可以在下面找到 - 看看,它很漂亮!
解决方案 2
优势
一旦
ConvertFromIntegral
函数完成,添加需要转换的新函数是微不足道的 - 只需在int32_t
、int64_t
和无符号等价物上写一个重载的集合。仅将模板的使用保留在一个地方,它们不会随着技术的重用而传播。
弊
- 使用
boost::enable_if
可能过于复杂。由于这只出现在一个地方,这在一定程度上有所缓解。
由于这是我自己的,我不能接受它,但如果你认为它很整洁,你可以投赞成票(显然有些人根本不认为它很整洁,这就是反对它的原因,我认为!感谢所有贡献想法的人!
该解决方案涉及从int
、long
和long long
到int32_t
和int64_t
的转换功能(对于无符号版本也是如此(。这与另一组重载在int32_t
、int64_t
和无符号等价物上的函数相结合。这两个函数可以组合使用,但第一个转换函数是一个可以重用的方便实用程序集,然后第二组函数非常简单。
// Utility conversion functions (reuse wherever needed)
template <class InputT>
typename boost::enable_if_c<sizeof(InputT)==sizeof(int32_t) && boost::is_signed<InputT>::value,
int32_t>::type ConvertFromIntegral(InputT z) { return static_cast<int32_t>(z); }
template <class InputT>
typename boost::enable_if_c<sizeof(InputT)==sizeof(int64_t) && boost::is_signed<InputT>::value,
int64_t>::type ConvertFromIntegral(InputT z) { return static_cast<int64_t>(z); }
template <class InputT>
typename boost::enable_if_c<sizeof(InputT)==sizeof(uint32_t) && boost::is_unsigned<InputT>::value,
uint32_t>::type ConvertFromIntegral(InputT z) { return static_cast<uint32_t>(z); }
template <class InputT>
typename boost::enable_if_c<sizeof(InputT)==sizeof(uint64_t) && boost::is_unsigned<InputT>::value,
uint64_t>::type ConvertFromIntegral(InputT z) { return static_cast<uint64_t>(z); }
// Overload set (mock implementation, depends on required return type etc)
void* objFromInt32 (int32_t i) { obj_from_int32(i); }
void* objFromInt64 (int64_t& i) { obj_from_int64(i); }
void* objFromUInt32(uint32_t& i) { obj_from_uint32(i); }
void* objFromUInt64(uint64_t& i) { obj_from_uint64(i); }
// Interface Implementation
MyClass(int z) : _val(objFromInt(ConvertFromIntegral(z))) {}
MyClass(long z): _val(objFromInt(ConvertFromIntegral(z))) {}
MyClass(long long z): _val(objFromInt(ConvertFromIntegral(z))) {}
MyClass(unsigned int z): _val(objFromInt(ConvertFromIntegral(z))) {}
MyClass(unsigned long z): _val(objFromInt(ConvertFromIntegral(z))) {}
MyClass(unsigned long long z): _val(objFromInt(ConvertFromIntegral(z))) {}
解决方案的简化(单个可编译.cpp
!(版本在 像"msg(long("这样的函数的不明确重载与候选"msg(int32_t("和"msg(int64_t("给出
给定 3个第三方函数...
void obj_from_int32( int32_bytes_t& i );
void obj_from_int64( int64_bytes_t& i );
void obj_from_uint32( uint32_bytes_t& i );
void obj_from_uint64( uint64_bytes_t& i );
您可以为内置类型调用"正确"的此类函数,如下所示:
template< int nBytes, bool isSigned >
struct ThirdParty;
template<>
struct ThirdParty< 4, true >
{
template< class IntegralT >
static void func( IntegralT& v )
{ obj_from_int32( v ) } // Add whatever conversion is required.
};
// Etc., specializations of ThirdParty for unsigned and for 8 bytes.
template< class IntegralT >
void myFunc( IntegralT& v )
{ ThirdParty< sizeof( v ), std::is_signed< IntegralT >::value >::func( v ); }
不是重载,而是模式匹配呢? 使用boost::enable_if
和帮助程序模板来选择您要查找的操作类型?
像这样:
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_integral.hpp>
#include <iostream>
template <typename T, typename Dummy=void> struct helper;
// Handle signed integers of size 1 (8 bits)
template <typename T> struct helper<T,
typename boost::enable_if_c<
boost::is_integral<T>::value &&
(sizeof(T)==1) &&
(static_cast<T>(-1) < static_cast<T>(0)) >::type>
{
static void do_stuff(T const& ) {std::cout<<"signed, size 1"<<std::endl;}
};
// Handle unsigned integers of size 1 (8 bits)
template <typename T> struct helper<T,
typename boost::enable_if_c<
boost::is_integral<T>::value &&
(sizeof(T)==1) &&
(static_cast<T>(-1) > static_cast<T>(0)) >::type>
{
static void do_stuff(T const& ) {std::cout<<"unsigned, size 1"<<std::endl;}
};
// Handle signed integers of size 2 (16 bits)
template <typename T> struct helper<T,
typename boost::enable_if_c<
boost::is_integral<T>::value &&
(sizeof(T)==2) &&
(static_cast<T>(-1) < static_cast<T>(0)) >::type>
{
static void do_stuff(T const& ) {std::cout<<"signed, size 2"<<std::endl;}
};
// And so on and so forth....
// Use a function for type erasure:
template <typename T> void do_stuff(T const& value)
{
helper<T>::do_stuff(value);
}
int main()
{
do_stuff(static_cast<unsigned char>(0)); // "unsigned, size 1"
do_stuff(static_cast<signed short>(0)); // "signed, size 2"
}
更完整的列表(并证明它至少适用于 GCC(在 http://ideone.com/pIhdq。
编辑:或者更简单,但覆盖范围可能较小:(使用标准积分类型(
template <typename T> struct helper2;
template <> struct helper2<uint8_t> {static void do_stuff2(uint8_t ) {...}};
template <> struct helper2<int8_t> {static void do_stuff2(int8_t ) {...}};
template <> struct helper2<uint16_t> {static void do_stuff2(uint16_t ) {...}};
template <> struct helper2<int16_t> {static void do_stuff2(int16_t ) {...}};
// etc.
template <typename T> void do_stuff2(T value) {helper2<T>::do_stuff2(value);}
正如我们在链接问题中发现的那样,长是这里歧义的原因。该行
MyClass(long z): _val(objFromInt(z)) {}
应更改为以下内容:
MyClass(long z): _val(sizeof(long) == 4 ? static_cast<int32_t>(z) : static_cast<int64_t>(z)))) {}
请注意,您可能会在 64 位 gcc 上遇到类似的长长问题。
正如其他答案中所指出的,这可以在运行时使用if(sizeof(int)==sizeof(int32_t))
样式分支轻松解决。要在编译时执行此操作,可以使用boost::enable_if
。
template <class InputT>
typename boost::enable_if_c<sizeof(InputT)==sizeof(int32_t) && boost::is_signed<InputT>::value,
int32_t>::type ConvertIntegral(InputT z) { return static_cast<int32_t>(z); }
template <class InputT>
typename boost::enable_if_c<sizeof(InputT)==sizeof(int64_t) && boost::is_signed<InputT>::value,
int64_t>::type ConvertIntegral(InputT z) { return static_cast<int64_t>(z); }
template <class InputT>
typename boost::enable_if_c<sizeof(InputT)==sizeof(uint32_t) && boost::is_unsigned<InputT>::value,
uint32_t>::type ConvertIntegral(InputT z) { return static_cast<uint32_t>(z); }
template <class InputT>
typename boost::enable_if_c<sizeof(InputT)==sizeof(uint64_t) && boost::is_unsigned<InputT>::value,
uint64_t>::type ConvertIntegral(InputT z) { return static_cast<uint64_t>(z); }
任何需要将整型类型转换为int32_t
、int64_t
、uint32_t
或uint64_t
只需调用如下:
ConvertIntegral(long(5)); // Will return a type compatible with int32_t or int64_t
ConvertIntegral
功能可以与int32_t
和int64_t
过载组相结合,以获得完整的解决方案。或者,所示技术可以内置到过载集中。
此外,可以通过禁用非整型类型来进一步增强上述内容。有关使用这些函数的完整示例,请参阅函数的不明确重载,例如"msg(long(",候选函数"msg(int32_t("和"msg(int64_t(">
义很容易源于有符号和无符号类型的重载。例如,给定
void foo(unsigned int);
void foo(long);
那么foo(0)
是模棱两可的,因为从int
到unsigned int
和long
的转化(或可能是促销(排名相同。
选择一个有符号,或者为每个签名编写两个重载集(如果您使用的是使用无符号类型的构造函数重载((并且您关心这一点(。
- C 字符串返回字符串的整数/双精度/长整型值
- 是什么导致了这种使用三进制而不是短整型的有符号int到无符号int转换
- 无法在 Arduino 中uint8_t数组转换为无符号长整型数组
- JNI 日期值转换问题,在C++中获取不同的长整型值
- 将长整型值打印为带有前导零的十六进制
- 为什么在传递长整型时调用具有两个双精度类型的参数的重载函数?
- 将整型常量映射到类型
- 将元组和整型实例合并到引用元组中
- 提升不良词法强制转换:将字符串转换为无符号长整型时,无法将源类型值解释为目标
- 为什么C++不允许两个同名的函数/类模板,区别仅在于非类型模板参数(整型)的类型?
- 将最小值整数转换为无符号长整型
- 如何将小端格式的QByteArray转换为无符号长整型
- 直接初始化无符号短整型的标准行为
- 在 C++ 中创建一对长整型和矢量时出现编译错误
- 应用于整型类型的编译时优化 'std::isfinite()'
- 枚举类的基础类型别名为整型类型(编译错误)
- 在编译时确定整型中的位数
- 编译宏以测试uint64_t和无符号长整型之间的差异
- 类在编译时隐式转换为整型(最好是bool)
- 为类型分配唯一的整型标识符,编译时