简体   繁体   English

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

[英]Function templates - compiler choosing function with different parameter types when calling with the same type

I was playing around with function templates and I stumbled across a weird interaction. 我正在玩功能模板,我偶然发现了一个奇怪的互动。

template<class T1, class T2>
void foo(T1, T1);

template<class T1, class T2>
void foo(T1, T2);

//main
foo(1,1)

This calls foo(T1, T2) and I don't understand why. 这调用foo(T1,T2),我不明白为什么。 How would that work? 那会怎么样? Are these functions overloads of each other, and why would the compiler choose the one with different parameter types? 这些函数是否相互重载,为什么编译器会选择具有不同参数类型的函数?

this particular interaction was explained in the first part of Henri Menke's post Henri Menke的帖子的第一部分解释了这种特殊的互动


After some more messing around I found something weirder 在经历了一些混乱后,我发现了一些更奇怪的东西

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

In this code I get a result 在这段代码中我得到了一个结果

different
different

but after commenting out the 1st call like 但在评论出第一个电话之后

int main()
{
    //foo(1, 1);
    foo<int, int>(1, 1);
}

the result is 结果是

same

I'm using VS2015 and if I write the same thing in Ideone ( like here ) the result for the 1st one is 我正在使用VS2015,如果我在Ideone中写同样的东西( 比如这里 ),第一个的结果是

different
same

Could somebody be able to explain what is (or isn't) going on? 有人能够解释发生了什么(或不发生了什么)?


By the way I came to the conclusion that the call foo<int, int>(1, 1); 顺便说一句,我得出的结论是调用foo<int, int>(1, 1); should be ambiguous. 应该是模棱两可的。 Both function templates have the same signature then and come from the same template. 两个功能模板都具有相同的签名,并且来自同一模板。 So that is another thing, why don't they collide? 那是另一回事,他们为什么不碰撞呢?

It is easy to see why this fails by simply deleting the second template, ie having a source file like 通过简单地删除第二个模板,即拥有类似的源文件,很容易看出为什么会失败

template<class T1, class T2>
void foo(T1, T1);

int main()
{
  foo(1,1);
}

This fails in Clang with the error 这在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.

The compiler has no way to deduce the second template parameter T2 . 编译器无法推导出第二个模板参数T2


If you delete the superfluous T2 from the first template and use this kind of source file 如果从第一个模板中删除多余的T2并使用此类源文件

template<class T1>
void foo(T1, T1);

template<class T1, class T2>
void foo(T1, T2);

int main()
{
  foo(1,1);
}

The compiler will always choose the the first option (if T1 and T2 are the same of course) because it is more specialised. 编译器将始终选择第一个选项(如果T1T2当然是相同的),因为它更专业。

Another option is to give T2 a default value. 另一种选择是给T2一个默认值。 Then the first variant can also be instantiated from foo(1,1) . 然后第一个变体也可以从foo(1,1)实例化。

template<class T1, class T2 = void>
void foo(T1, T1);

Another interesting thing is this: 另一个有趣的事情是:

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

This will output at runtime: 这将在运行时输出:

First choice!

I'm not entirely sure, but I believe this is because in the case of deduction (even though it is not carried out here), for the first variant the compiler would have to deduce only one type instead of two which makes it the more specialised option. 我不完全确定,但我相信这是因为在演绎的情况下(即使这里没有执行),对于第一个变体,编译器必须只推导出一种类型而不是两种类型,这使得它更多专业选择。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM