Emi*_*son 20 c++ templates overload-resolution
#include <iostream>
struct A {};
struct B : public A {};
template<typename T>
void foo(const T &x) { std::cout << "Called template" << std::endl; }
void foo(const A &a) { std::cout << "Called A" << std::endl; }
int main()
{
foo(A());
foo(B());
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这打印:
Called A
Called template
Run Code Online (Sandbox Code Playgroud)
我的印象是,总是会在模板函数上选择合适的非模板函数.有人可以向我解释导致这种有些令人惊讶的结果的解决步骤吗?
Rei*_*ica 16
我的印象是,总是会在模板函数上选择合适的非模板函数.
这仅适用于模板和非模板同样适合的候选者.这就是选择非模板的原因foo(A()).
但是,在foo(B())使用非模板的情况下,需要派生到基础的转换.因此功能模板严格更好,因此它被选中.
该foo模板实例化到void foo(const B&).考虑一下没有模板会是什么样子:
void foo(const B &x) { std::cout << "Called template" << std::endl; }
void foo(const A &a) { std::cout << "Called A" << std::endl; }
Run Code Online (Sandbox Code Playgroud)
我相信你会同意,foo(B())应该毫不含糊地选择第一个.这就是选择模板的原因.
n3376 13.3.3.1/6
当参数具有类类型且参数表达式具有派生类类型时,隐式转换序列是从派生类到基类的派生到基础的转换.
n3376 13.3.3.1/8
如果不需要转换来将参数与参数类型匹配,则隐式转换序列是由标识转换(13.3.3.1.1)组成的标准转换序列.
身份转换在13.3.3.1.1 /表12中具有完全匹配等级到期表,但是派生到基础比身份更差.
因此,编译器在第一种情况下只有候选者
// template after resolving
void foo(const A&)
// non-template
void foo(const A&)
Run Code Online (Sandbox Code Playgroud)
两者都有身份等级,但由于第一个是功能模板,因此将选择第二个.在第二种情况下
// template after resolving
void foo(const B&)
// non-template
void foo(const A&)
Run Code Online (Sandbox Code Playgroud)
只有第一个具有身份等级并将被选中.