MSVC中std::type_info::name()在unsigned long long作为非类型模板参数时是否存在Bug?
我一直觉得挺有意思的小细节:MSVC在所有诊断消息里都用__int64来指代long long类型——比如你执行std::cout << typeid(long long).name();时,它输出的是__int64。虽然有点另类,但倒也不影响使用,毕竟类型本身的行为完全符合64位整数的预期。不过今天我碰到了unsigned long long的麻烦事,根源出在<typeinfo>头文件里std::type_info类的name()成员函数上:unsigned __int64(MSVC对unsigned long long的内部称呼)似乎没享受到和其他内置整数类型一样的“待遇”。
我写了一段测试代码来复现问题:
// main.cpp #include <iostream> #include <limits> #include <string> template < typename Int , Int Max = std::numeric_limits<Int>::max() > struct foo { static Int max() { return Max; } static std::string name() { return typeid(foo).name(); // 这里是不是有问题? } }; int main() { // 大多数无符号整数类型都能正常工作 std::cout << foo<unsigned int>::name() << "\nmax: " << foo<unsigned int>::max() << "\n\n"; // 但unsigned __int64(也就是unsigned long long)不行 std::cout << foo<unsigned long long>::name() << "\nmax: " << foo<unsigned long long>::max() << "\n\n"; } // end file: main.cpp
在MSVC下运行这段代码,输出是这样的:
struct foo<unsigned int,4294967295> max: 4294967295 struct foo<unsigned __int64,-1> max: 18446744073709551615
你看这里的矛盾点:
- 对于
unsigned int,typeid(foo).name()输出的模板参数里,最大值4294967295是正确的无符号值,和max()函数返回的结果一致; - 但对于
unsigned long long,name()输出的模板参数最大值变成了-1,可max()函数返回的却是正确的无符号最大值18446744073709551615。
我测试了所有内置无符号整数类型,只有unsigned long long会出现这个问题——其他类型的name()输出都能正确显示无符号最大值。这说明微软的本意应该是要输出正确的无符号值,毕竟其他类型都没问题,所以我怀疑这是MSVC的一个编译器bug。
补充一下:我用的是最新版的MSVC,编译时开启了/std:c++23preview选项。另外我对比了g++和Clang的输出,它们的typeid(...).name()返回的是经过名字修饰(mangled)的字符串,不存在这个问题。
从现象来看,这大概率是MSVC在处理unsigned __int64作为非类型模板参数时,typeid(...).name()的字符串生成逻辑出了疏漏:把无符号类型的最大值错误地按有符号类型解析成了-1,属于明显的不一致行为,应该是一个未被正确处理的bug。如果要确认是否是已知bug,可以去微软的开发者社区或者GitHub仓库查询相关的issue。
内容来源于stack exchange

