VS2017中非类型参数包展开异常的技术问询
VS2017中模板参数包展开的奇怪输出问题
嘿,我来帮你拆解这个让人困惑的C++模板问题~
先来看你提供的原代码:
#include <iostream> #include <typeinfo> template <size_t... s> struct str { typedef void(&ftype)(decltype(s)...); }; int main() { std::cout << typeid(str<3, 4, 5>::ftype).name() << std::endl; }
你提到在VS2017里编译运行这段代码,输出是int __cdecl(unsigned int),但按照对参数包...运算符的理解,这里应该把3,4,5对应的类型全部展开,也就是函数类型应该是接受三个unsigned int参数的void函数引用,对吧?
问题根源
这其实是VS2017对C++模板特性支持不完善导致的bug:
- 首先,非类型模板参数
s的每个元素类型都是size_t(对应VS里的unsigned int),按照参数包展开规则,decltype(s)...应该被展开成size_t, size_t, size_t,对应的函数类型应为void(&)(size_t, size_t, size_t)。 - 但VS2017不仅错误地只展开了一个参数,还把函数的返回类型搞错成了
int(明明我们定义的是void),这属于旧版本编译器对C++11模板规则的解析漏洞。
验证与修正方法
你可以通过两种方式确认问题所在:
验证参数包本身是否正常展开:
用sizeof...来检查参数包的元素数量,代码如下:#include <iostream> template <size_t... s> struct count { static constexpr size_t value = sizeof...(s); }; int main() { std::cout << count<3,4,5>::value << std::endl; // 输出3,说明参数包确实是3个元素 }这证明参数包本身的展开是正常的,只是
typeid的输出有问题。修正函数类型的定义方式:
换一种更明确的展开写法,让VS2017能正确识别:#include <iostream> #include <typeinfo> template <size_t... s> struct str { // 先定义模板函数类型,再代入参数包展开结果 template <typename... Args> using func_template = void(&)(Args...); using ftype = func_template<decltype(s)...>; }; int main() { std::cout << typeid(str<3, 4, 5>::ftype).name() << std::endl; }或者更省心的方式:直接升级到VS2019及以后的版本,新版本编译器对C++标准的支持更完善,能正确输出预期的函数类型。
内容的提问来源于stack exchange,提问作者IS4
相关产品推荐
相关产品推荐

