我正在玩功能模板,偶然发现了一个奇怪的互动。
template<class T1, class T2>
void foo(T1, T1);
template<class T1, class T2>
void foo(T1, T2);
//main
foo(1,1)
这调用了foo(T1,T2),我不明白为什么。那会怎么样?这些函数是否相互重载,为什么编译器会选择具有不同参数类型的函数?
Henri Menke的帖子的第一部分解释了这种特殊的互动
在经历了一些混乱后,我发现了一些奇怪的东西
#include <iostream>
template<class T1, class T2>
void foo(T1 a, T1 b)
{
std::cout << "same\n";
}
template<class T1, class T2>
void foo(T1 a, T2 b)
{
std::cout << "different\n";
}
int main()
{
foo(1, 1);
foo<int, int>(1, 1);
}
在此代码中,我得到一个结果
different
different
但在评论第一个电话之后
int main()
{
//foo(1, 1);
foo<int, int>(1, 1);
}
结果是
same
我正在使用VS2015,如果我在Ideone(like here)中写相同的内容,那么第一个的结果是
different
same
有人能够解释发生了什么(或不发生了什么)?
顺便说一下,我得出结论,呼叫foo<int, int>(1, 1);
应该是模棱两可的。两个功能模板都具有相同的签名,并且来自同一模板。那是另一回事,他们为什么不碰撞?
答案 0 :(得分:4)
通过简单地删除第二个模板,即拥有像
这样的源文件,很容易看出为什么会失败template<class T1, class T2>
void foo(T1, T1);
int main()
{
foo(1,1);
}
Clang的错误
失败test.cpp:6:3: error: no matching function for call to 'foo'
foo(1,1);
^~~
test.cpp:2:6: note: candidate template ignored: couldn't infer template argument
'T2'
void foo(T1, T1);
^
1 error generated.
编译器无法推断出第二个模板参数T2
。
如果您从第一个模板中删除多余的T2
并使用此类源文件
template<class T1>
void foo(T1, T1);
template<class T1, class T2>
void foo(T1, T2);
int main()
{
foo(1,1);
}
编译器将始终选择第一个选项(如果T1
和T2
当然相同),因为它更专业。
另一种选择是给T2
一个默认值。然后,第一个变体也可以从foo(1,1)
实例化。
template<class T1, class T2 = void>
void foo(T1, T1);
另一个有趣的事情是:
#include <iostream>
template<class T1, class T2>
void foo(T1, T1)
{ std::cout << "First choice!\n"; }
template<class T1, class T2>
void foo(T1, T2)
{ std::cout << "Second choice!\n"; }
int main()
{
foo<int,int>(1,1);
}
这将在运行时输出:
First choice!
我不完全确定,但我相信这是因为在演绎的情况下(即使这里没有执行),对于第一个变体,编译器必须只推导出一种类型而不是两种类型它是更专业的选择。