模板函数重载与const

Nic*_*ick 0 c++ templates

这是一些代码:

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过载?

T.C*_*.C. 7

对于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选择非模板而不是函数模板特化.