这是一些代码:
template<class T>
inline void bar(T& t) {
foo(t); // intention is that foo() is found by ADL
}
struct Wig {
int i;
};
void foo(int){ }
// some convenience overload
inline void bar(const Wig& w) { foo(w.i); }
// The bit that if uncommented, "fixes" the problem
//inline void bar(Wig& w) { foo(w.i); }
int main()
{
Wig w;
bar(w);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
Clang 3.5和Gcc 4.7,吐出以下错误:
template-function-overload.cpp:12:4: error: no matching function for call to 'foo'
foo(t);
^~~
template-function-overload.cpp:29:4: note: in instantiation of function template specialization
'bar<Wig>' requested here
bar(w);
^
template-function-overload.cpp:19:6: note: candidate function not viable: no known conversion from
'Wig' to 'int' for 1st argument
void foo(int){ }
^
Run Code Online (Sandbox Code Playgroud)
所以它看起来不像编译器问题.
另外,注释掉非const重载会修复错误.
为什么这段代码不正确,为什么需要非const过载?
对于bar(w)呼叫,重载决策比较
void bar<Wig>(Wig&); // instantiated from the template
void bar(const Wig &);
Run Code Online (Sandbox Code Playgroud)
绑定到较少cv限定类型的引用更好([over.ics.rank],bullet 3.2.6),因此选择第一个签名.该模板试图调用fooa Wig,但是没有这样的东西,因此错误.
使用额外的非常量重载,我们现在正在比较(加上const Wig &那个比其中任何一个更糟):
void bar<Wig>(Wig&); // instantiated from the template
void bar(Wig&);
Run Code Online (Sandbox Code Playgroud)
参数类型是相同的,因此通过对转换序列进行排序,两者无法区分,而[over.match.best] bullet 1.6中的tiebreaker选择非模板而不是函数模板特化.