下面的代码中,为什么模板函数的显式扩展foo无法编译,而 的扩展却bar编译成功?实时链接 - https://godbolt.org/z/o8Ea49KEb
template <typename T1, typename T2>\nT1 foo(T2) { T2(42); return T1{}; };\n\ntemplate <typename T1, typename T2>\nT1 bar(void) { T2(42); return T1{}; };\n\nint main()\n{\n foo<int, void>(); // fails\n\n bar<int, void>(); // works\n}\nRun Code Online (Sandbox Code Playgroud)\nT2请注意,两个函数的主体中都使用了模板参数,唯一的区别是函数参数 tobar已被手动替换。
这个问题是在阅读std::conditional - Invalid argument type \xe2\x80\x98void\xe2\x80\x99 即使在测试 \'void\'并试图简化问题时受到启发的。
\nasc*_*ler 24
(void)参数列表与空参数列表相同的规则可以在 C++ 标准[dcl.fct]/4()中找到:
由非依赖类型的单个未命名参数组成的参数列表
void相当于空参数列表。除这种特殊情况外,参数不得具有cvvoid类型。
这个问题的重要部分是“非依赖类型”。模板参数T与类型相关,因此它不会触发规则。
我认为标准有这条规则,因为如果实例化恰好使该参数类型为通常采用一个参数的模板函数可能突然变成零参数函数,那么它也会非常混乱(我想说更糟)void。有了这条规则,我们就知道当一个模板用参数声明时,它确实有一个参数。
小智 5
考虑以下:
template<typename T>
void foo(T) {}
void bar(void) {}
Run Code Online (Sandbox Code Playgroud)
您假设foo<void>和bar(void)是等价的,但它们不是。foo<T>总是需要争论。所以foo<void>相当于一个函数baz(void x)。这不会编译,因为您不能拥有 void 类型的值。这与您收到的错误消息相同。
在函数签名中,void bar(void)括号中的 void 表示不同的含义:没有参数的函数。这是C的残余,不推荐。
函数bar<void>(T) 和baz(void x)不能存在,因为它们都需要类型 的值void,而该值不能存在。
模板函数的解决方案是为模板实例化非法的情况提供重载或专门化。
template<typename T>
void foo(T) {} // one argument
void foo() {} // no arguments -> different signatures -> overload
template<typename T>
void bar() {} // no arguments
template<>
void bar<void> {} // still no arguments -> same signature -> specialisation
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2201 次 |
| 最近记录: |