Nick
Nick

Reputation: 961

template function overload with const

Here is a bit of code:

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 and Gcc 4.7, spit out the following error:

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){ }
     ^

So it doesn't look like a compiler issue.

Also, commenting out the non-const overload fixes the error.

Why is this code incorrect, and why a non-const overload required?

Upvotes: 0

Views: 1169

Answers (1)

T.C.
T.C.

Reputation: 137394

For the bar(w) call, overload resolution compares

void bar<Wig>(Wig&); // instantiated from the template
void bar(const Wig &);

Binding to a reference to a less cv-qualified type is better ([over.ics.rank], bullet 3.2.6), so the first signature is chosen. That template attempts to call foo on a Wig, but there's no such thing, hence the error.

With the extra non-const overload, we are now comparing (plus the const Wig & that's worse than either):

void bar<Wig>(Wig&); // instantiated from the template
void bar(Wig&);

The parameter types are identical, so the two are indistinguishable by ranking conversion sequences, and instead the tiebreaker in [over.match.best] bullet 1.6 selects the non-template over the function template specialization.

Upvotes: 7

Related Questions