以下是一些代码:
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;
}
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){ }
^
所以它看起来不像编译器问题。
另外,注释掉非const重载会修复错误。
为什么这段代码不正确,以及为什么需要非const重载?
答案 0 :(得分:7)
对于bar(w)
调用,重载决策比较
void bar<Wig>(Wig&); // instantiated from the template
void bar(const Wig &);
绑定到较少cv限定类型的引用更好([over.ics.rank],bullet 3.2.6),因此选择第一个签名。该模板尝试在foo
上调用Wig
,但是没有这样的事情,因此错误。
由于额外的非常数超载,我们现在正在比较(加上比其中任何一个更糟的const Wig &
):
void bar<Wig>(Wig&); // instantiated from the template
void bar(Wig&);
参数类型是相同的,因此通过对转换序列进行排序,两者无法区分,而[over.match.best] bullet 1.6中的tiebreaker选择非模板而不是函数模板专门化。