函数模板 - 当使用相同类型调用时,编译器选择具有不同参数类型的函数

时间:2017-04-30 22:16:02

标签: c++ function templates

我正在玩功能模板,偶然发现了一个奇怪的互动。

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);应该是模棱两可的。两个功能模板都具有相同的签名,并且来自同一模板。那是另一回事,他们为什么不碰撞?

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);
}

编译器将始终选择第一个选项(如果T1T2当然相同),因为它更专业。

另一种选择是给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!

我不完全确定,但我相信这是因为在演绎的情况下(即使这里没有执行),对于第一个变体,编译器必须只推导出一种类型而不是两种类型它是更专业的选择。