partial ordering of template functions

Quote:

>>>Is partial ordering of template functions supposed to be working in VC++

>>>.NET? I'm getting some very peculiar results. Have a look at the

> following

>>>code

>>>#include <iostream>

>>>using namespace std;

>>>class X {};

>>>// swap these lines for bug

>>>template <class T, class U> void operator+(const T& x, const U& y);

>>>template <class T> void operator+(const T& x, const T& y);

>>>template <class T, class U>

>>>void operator+(const T& x, const U& y)

>>>{

>>>cout << "diff\n";

>>>}

>>>template <class T>

>>>void operator+(const T& x, const T& y)

>>>{

>>>cout << "same\n";

>>>}

>>>int main()

>>>{

>>>X x;

>>>x + 2;

>>>x + x;

>>>}

>>>This prints

>>>diff

>>>same

>>>which I think is the right result. However if I swap the two prototypes

>>>above (see comment) I get

>>>diff

>>>diff

>>>Wierd. Perhaps even stranger if I replace operator+ with a regular

> function

>>>(called func, say) I get the error message

>>>c:\Projects\test\main.cpp(60): error C2667: 'func' : none of 2 overloads

>>>have a best conversion

>>>Other apparently harmless transformations have strange effects, for

> instance

>>>replacing x + 2 with operator+(x, 2) or replacing const T& with T.

>>>Does anyone else have any experiences with this? As it happens the

> working

>>>code above is exactly what I want to do but the whole area seems a

> little

>>>fragile.

>>>Is partial ordering supposed to be working in the current version of

> VC++

>>>.NET or is it one of the things scheduled for the 2003 release?

>>>Thanks,

>>>John

>>hi, John. These guys definitely know more details about the compiler

> itself

>>than me. But let's take a logical look at your problem. You have:

>>template <class T, class U> void operator+(const T& x, const U& y);

>>template <class T> void operator+(const T& x, const T& y);

>>Consider the x + 2 statement. It is unwound to:

>>template <X, int> void operator+(const X& x, const int& y);

>>template <X> void operator+(const X& x, const X& y);

>>So definitely the 1st function is better. Now consider x + x:

>>template <X, X> void operator+(const X& x, const X& y);

>>template <X> void operator+(const X& x, const X& y);

>>So as you may see ignoring template signature we have absolutely identical

>>functions, namely:

>>void operator+(const X& x, const X& y); //diff

>>void operator+(const X& x, const X& y); //same

>>Thus, what should a compiler do? Apparently, take the very last definition

>>of the function. Therefore, for the case when you have

>>void operator+(const X& x, const X& y); //same

>>void operator+(const X& x, const X& y); //diff

>>diff

>>diff

>>is printed. Where does my logic have a flaw?

>>-d

> Good explanation, it might even be right! Doesn't explain why the compiler

> can't manage the same if the operator is a function, or if const T& is

> changed to T however.

> john

Okay, so for this code:

template <class T> void foo(const T& x, const T& y);

template <class T, class U> void foo(const T& x, const U& y);

template <class T>

void foo(const T& x, const T& y)

{

cout << "same\n";

Quote:

}

template <class T, class U>

void foo(const T& x, const U& y)

{

cout << "diff\n";

Quote:

}

int main()

{

X x;

foo(x, 2); //line #48

foo(x, x); //line #49

Quote:

}

you might be having (at least I do):

1.cpp(49) : error C2667: 'foo' : none of 2 overloads have a best conversion

1.cpp(26): could be 'void foo(const T &,const U &)'

1.cpp(24): or 'void foo(const T &,const T &)'

while trying to match the argument list '(X, X)'

1.cpp(49) : error C2668: 'foo' : ambiguous call to overloaded function

1.cpp(26): could be 'void foo(const T &,const U &)'

1.cpp(24): or 'void foo(const T &,const T &)'

while trying to match the argument list '(X, X)'

No questions about $48, right? What unwinding we have again:

template <class T = X> void foo(const X& x, const X& y);

template <class T = X, class U = X> void foo(const X& x, const X& y);

so how to resolve an ambiguity if we have two identical signatures? No way!

For whatever you want to change arguments, it will not work:

template <class T = X> void foo(const X x, const X &y);

template <class T = X, class U = X> void foo(const X &x, const X y);

What is the difference actually? Indeed, no matter what are the arguments,

either const T x, or const T& x, or X x, or X& x, it makes difference -

ambiguity still exists though with some additional problems like operator =.

-d