1

Consider this very simple example, where I have template wrapper class for which are defined operators:

template <class T>
struct W {
   W(const T&) {}
};
template <class T> 
T operator + (const W<T>& w1, const W<T>& w2) { return T(); }

And this surprisingly cannot match for wrapped type, with simple error from gcc4.5.1 that cannot find operator + (A,A):

struct A {};
int main() {
  A a1, a2;
  A a3 = a1 + a2;
}

I've tried to find the reason by testing non template wrapper, but this version works:

struct A {};
struct WA {
   WA(const A&) {}
}; 
A operator + (const WA& w1, const WA& w2) { return A(); }
int main() {
  A a1, a2;
  A a3 = a1 + a2;
}

What is the reason of such difference of arguments matching, and what to do to make template version works?

[UPDATE]

I took your answers into consideration, and I've changed the example to be a little opposite way, still with the same results - template version is complaining for missing operator +, while non template works fine. Now I have explicit cast operator to explicit wrapper class:

template version

template <class T>
struct W {
};
template <class T> 
T operator + (const W<T>& w1, const W<T>& w2) { return T(); }

struct A {
 operator W<A>() const { return W<A>(); }
};

not template

struct WA {
}; 
struct A {
 operator WA() const { return WA(); }
};

A operator + (const WA& w1, const WA& w2) { return A(); }

I am trying to avoid this solution:

A a3 = W(a1) + W(a2);

No hope for this to work?

A a3 = a1 + a2;
PiotrNycz
  • 23,099
  • 7
  • 66
  • 112

2 Answers2

4

Template argument deduction comes before overload resolution. But template argument deduction does not consider implicit conversions, so your templated operator is never even considered.

Implicit conversions are only applied after an overload has been chosen.

You can say A a3 = W(a1) + W(a2);, though.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
2

Your first example fails because the standard says it must fail with templates. There are potential problems with argument dependent name lookup, and templates exacerbate those problems. One way around this is to preclude templates from such lookup unless you are explicit about the use of templates. Here's the relevant text from the C++03 standard, paragraph 6 of section 14.8.1:

For simple function names, argument dependent lookup (3.4.2) applies even when the function name is not visible within the scope of the call. This is because the call still has the syntactic form of a function call (3.4.1). But when a function template with explicit template arguments is used, the call does not have the correct syntactic form unless there is a function template with that name visible at the point of the call. If no such name is visible, the call is not syntactically well-formed and argument-dependent lookup does not apply. If some such name is visible, argument dependent lookup applies and additional function templates may be found in other namespaces.

Update:
The question has been edited with additional information.

I am trying to avoid this solution:
A a3 = W(a1) + W(a2);

Why, exactly, are you trying to avoid that situation? This code of yours violates two key rules of programming.

  1. Code as if the next guy to maintain your code is a homicidal maniac who knows where you live.
  2. Principle of least astonishment.

Even your non-template version violates these rules. You compute a1+a2 by a (hidden) conversion to an unrelated class W, the operator+ of which returns an A rather than a W. This is not the principle of least astonishment. This is astonishing, to say the least. Why don't you think making your conversions explicit is a better approach?

Argument dependent lookup is a very powerful tool, but there are a lot of problems that are associated with this power. Couple ADL with automatic type conversions and the problems magnify. Couple it with automatic type conversions and templates and you have a mess. The standard committee decided enough was enough. You cannot do what you want to do unless you make the conversions explicit.

David Hammen
  • 32,454
  • 9
  • 60
  • 108
  • What does it mean that "a function template with that name visible at the point of that call" – PiotrNycz Oct 05 '12 at 23:02
  • I did not notice your update earlier. I agree, but... this is not real code. I just use it as example to show only the problem not all "surroundings". Consider that posters here are always asked to post a code only showing the problem, but then they are criticized for programming in silly way... I will remember to add note that code is only artificial illustration. – PiotrNycz Oct 15 '12 at 00:15