我在使用C++类型特征时遇到了一些奇怪的行为,并将我的问题缩小到这个古怪的小问题,我将给出大量的解释,因为我不想留下任何误解的东西.
假设您有这样的程序:
#include <iostream>
#include <cstdint>
template <typename T>
bool is_int64() { return false; }
template <>
bool is_int64<int64_t>() { return true; }
int main()
{
std::cout << "int:\t" << is_int64<int>() << std::endl;
std::cout << "int64_t:\t" << is_int64<int64_t>() << std::endl;
std::cout << "long int:\t" << is_int64<long int>() << std::endl;
std::cout << "long long int:\t" << is_int64<long long int>() << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在使用GCC(以及32位和64位MSVC)进行32位编译时,程序的输出将为:
int: 0
int64_t: 1
long int: 0
long long int: 1
Run Code Online (Sandbox Code Playgroud)
但是,由64位GCC编译产生的程序将输出:
int: 0
int64_t: 1
long int: 1
long long int: 0
Run Code Online (Sandbox Code Playgroud)
这是好奇的,因为long long int是有符号的64位整数,并且为所有意图和目的,等同于long int和int64_t类型,所以在逻辑上,int64_t,long int和long long int将等效类型-使用这些类型时所产生的组件是相同的.一看就stdint.h告诉我原因:
# if __WORDSIZE == 64
typedef long int int64_t;
# else
__extension__
typedef long long int int64_t;
# endif
Run Code Online (Sandbox Code Playgroud)
在64位编译中,int64_t是long int,而不是long long int(显然).
解决这种情况非常简单:
#if defined(__GNUC__) && (__WORDSIZE == 64)
template <>
bool is_int64<long long int>() { return true; }
#endif
Run Code Online (Sandbox Code Playgroud)
但这是可怕的hackish并且不能很好地扩展(物质的实际功能uint64_t等). 所以我的问题是:有没有办法告诉编译器a long long int也是a int64_t,就像long int是?
我最初的想法是,由于C/C++类型定义的工作方式,这是不可能的.没有办法为编译器指定基本数据类型的类型等价,因为这是编译器的工作(并允许它可以打破很多东西)并且typedef只采用单向方式.
我也不太关心在这里得到一个答案,因为这是一个超级优秀的边缘案例,我不怀疑任何人都会关心什么时候这些例子不是很可怕(这是否意味着这应该是社区维基?) .
附加:我之所以使用部分模板特化而不是更简单的示例,例如:
void go(int64_t) { }
int main()
{
long long int x = 2;
go(x);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
是说所述示例仍然会编译,因为long long int可以隐式转换为int64_t.
追加:到目前为止,唯一的答案是假设我想知道类型是否为64位.我不想误导人们认为我关心这一点,并且可能应该提供更多关于这个问题表现出来的例子.
template <typename T>
struct some_type_trait : boost::false_type { };
template <>
struct some_type_trait<int64_t> : boost::true_type { };
Run Code Online (Sandbox Code Playgroud)
在这个例子中,some_type_trait<long int>将是一个boost::true_type,但some_type_trait<long long int>不会.虽然这在C++的类型概念中是有意义的,但这是不可取的.
另一个例子是使用类似限定符same_type(这在C++ 0x Concepts中很常见):
template <typename T>
void same_type(T, T) { }
void foo()
{
long int x;
long long int y;
same_type(x, y);
}
Run Code Online (Sandbox Code Playgroud)
该示例无法编译,因为C++(正确地)看到类型不同.g ++将无法编译,错误如下:没有匹配的函数调用same_type(long int&, long long int&).
我想强调,我理解为什么会发生这种情况,但我正在寻找一种不会强迫我在整个地方重复代码的解决方法.
MSa*_*ers 47
你不需要去64位看这样的东西.考虑int32_t常见的32位平台.它可能是typedef' int或作为一个long,但显然只是两者中的一个.int和long当然是不同的类型.
不难看出int == int32_t == long在32位系统上没有解决方法.出于同样的原因,没有办法long == int64_t == long long在64位系统上进行.
如果可以的话,可能的后果对于重载的代码来说会相当痛苦foo(int),foo(long)并且foo(long long)- 突然他们对同一个重载有两个定义?!
正确的解决方案是您的模板代码通常不应该依赖于精确类型,而是依赖于该类型的属性.same_type对于特定情况,整个逻辑仍然可以:
long foo(long x);
std::tr1::disable_if(same_type(int64_t, long), int64_t)::type foo(int64_t);
Run Code Online (Sandbox Code Playgroud)
即,过载foo(int64_t)时,它没有定义完全相同一样foo(long).
[编辑]使用C++ 11,我们现在有一种标准的方式来编写它:
long foo(long x);
std::enable_if<!std::is_same<int64_t, long>::value, int64_t>::type foo(int64_t);
Run Code Online (Sandbox Code Playgroud)
你想知道一个类型是否与int64_t类型相同,或者你想知道某些东西是64位吗?根据您提出的解决方案,我认为您在询问后者.在那种情况下,我会做类似的事情
template<typename T>
bool is_64bits() { return sizeof(T) * CHAR_BIT == 64; } // or >= 64
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
146445 次 |
| 最近记录: |