【发布时间】:2020-07-18 00:25:08
【问题描述】:
主题看起来有点混乱,但是我不知道如何更恰当地表述它,对不起=)
我们看下面的代码
#include <iostream>
template<typename T>
void f(T value) {
std::cout << "f<T>" << std::endl;
}
template<>
void f(int value) {
std::cout << "f<int>" << std::endl;
}
template<typename T>
struct S {
using type = T;
};
template<typename T>
void f(typename S<T>::type value) {
std::cout << "f<S<T>>" << std::endl;
};
int main() {
f(123);
f<int>(123);
}
输出是
$ ./testgcc
f<int>
f<S<T>>
所以问题是为什么第一次调用会导致f<int> 特化,而第二次使用显式int 模板参数会导致调用“模板化”f<S<int>>()?标准中是否有规定如何在这种情况下实例化模板?
提前致谢!
PS 使用不同版本的 gcc 和 clang 进行测试 - 行为是相同的。我没有 Windows 系统可以用 MSVC 进行测试,但是我在 Godbolt 上进行了测试,MSVC 结果如下:
_main PROC
; ....
push 123 ; 0000007bH
call void f<int>(int) ; f<int>
add esp, 4
push 123 ; 0000007bH
call void f<int>(int) ; f<int>
; ...
所以 MSVC 在这两种情况下都会调用 f<int>。此行为是否记录为实现定义?
【问题讨论】:
-
这已涵盖here。两者在功能上等价,因为“对于任何给定的模板参数集,两个表达式的求值结果相同”。然后稍后:“如果程序包含功能等价但不等价的函数模板声明,则该程序格式错误;不需要诊断。”
-
如果
int不应该,那么哪些类型应该使用 S版本?你如何决定? -
“此行为是否记录为实现定义?” 不,它要么是编译器中的错误,要么是格式错误的程序 NDR 或 UB。