Bug 16053 - Fails to identify overload
Summary: Fails to identify overload
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 3.4.0
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2004-06-18 11:20 UTC by Ivan Godard
Modified: 2005-07-23 22:49 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments
Compiler output (-v -save-temps) (740 bytes, text/plain)
2004-06-18 11:21 UTC, Ivan Godard
Details
Source code (-save-temps) (112.49 KB, text/plain)
2004-06-18 11:24 UTC, Ivan Godard
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Ivan Godard 2004-06-18 11:20:44 UTC
Fails to identify overload, although it lists the overload it should be
identifying right in the error message.
Comment 1 Ivan Godard 2004-06-18 11:21:41 UTC
Created attachment 6555 [details]
Compiler output (-v -save-temps)
Comment 2 Ivan Godard 2004-06-18 11:24:07 UTC
Created attachment 6556 [details]
Source code (-save-temps)
Comment 3 Wolfgang Bangerth 2004-06-18 14:00:27 UTC
(You should really learn to write _small_ testcases -- you'd save 
everyone a lot of time that way...) 
 
Here's a reduced testcase: 
---------------------- 
class B {}; 
 
template <typename> struct A { 
    template <typename U> 
    friend void operator<< (A &, const U &); 
}; 
 
template<typename T> 
void operator<<(A<T> &, const B &); 
 
int main() { 
  A<int> d; 
  d << B(); 
} 
----------------------------- 
 
With gcc, we get this error: 
g/x> /home/bangerth/bin/gcc-3.4-pre/bin/c++ -w -c x.cc 
x.cc: In function `int main()': 
x.cc:13: error: ambiguous overload for 'operator<<' in 'd << B()' 
x.cc:9: note: candidates are: void operator<<(A<T>&, const B&) [with T = int] 
x.cc:5: note:                 void operator<<(A< <template-parameter-1-1> >&, 
const U&) [with U = B, <template-parameter-1-1> = int] 
 
I think gcc is completely correct in printing this error: both functions 
are exact matches, but only after template parameter unification. Why do 
you think that gcc should accept the code? 
 
W. 
 
 
PS: With icc, we get this: 
g/x> icc -c -Xc -ansi x.cc 
x.cc(13): error: more than one operator "<<" matches these operands: 
            function template "operator<<(A<int> &, const U &)" 
            function template "operator<<(A<T> &, const B &)" 
            operand types are: A<int> << B 
    d << B(); 
      ^ 
 
compilation aborted for x.cc (code 2) 
 
Comment 4 Ivan Godard 2004-06-18 23:13:04 UTC
Well, as I understand it, an exact match on a non-template argument trumps any template match in the same position of an overload; this is the essence of specialization. I also understand that a "friend" declaration within a class is the equivalent (for identification purposes) to the same declaration outside the class with appropriate substitutions, i.e. friendship is irrelevant for call indentification, and only matters in the body.

In your reduced case, after removing the "friend" to outside the class manually (to mimic export of friends as performed by the compiler), your example becomes equivalent to:

class B {};

template <typename> struct A { };

template <typename T, typename U>
void operator<< (A<T> &, const U &);

template<typename T>
void operator<<(A<T> &, const B &);

int main() {
  A<int> d;
  d << B();
  }

which is exactly what you would have written had you *not* had to make one of the overloads a friend.

Expessed in this form it is clear that the latter overload is essentially a specialization of the former and the call should identify the latter. Which in fact it does if you compile the rewritten case.

Now it seems to me that identification should not depend upon whether a function had been made a friend or not. I don't understand the standard enough to know whether my two functions (as rewritten to remove "friend") are ambiguous, but if they are they should be ambiguous in both your version and my rewrite. Or neither. Half and half is unreasonable, as these are clearly the same declarations.

I believe (in my ignorance) that the compiler has it right on the rewritten version, and is failing to correctly export the friend to the surrounding scope in your version; considering the number of other bugs in friend export this would not be surprising.

Ivan
Comment 5 Andrew Pinski 2004-06-19 06:14:24 UTC
In fact with "Comeau C++ Online", it also rejects reduced code so this is not a bug.  The issue is more 
complex than what you said for friends as templates are involved.
Comment 6 Wolfgang Bangerth 2004-06-19 19:28:23 UTC
icc 8, on the other hand accepts it. Initially, I had thought that in 
both cases of my example in comment #3 the compiler has to match 
exactly one template argument. In that case, an ambiguity would have 
been unavoidable. In fact, however, it has to match two template 
arguments for the friend function, and one for the non-friend. That's 
a case where partial ordering comes into play. 
 
I am not sure any more whether my analysis of my testcase is correct, 
and would like to solicit other opinions. 
 
W. 
Comment 7 Kriang Lerdsuwanakij 2004-07-11 15:10:49 UTC
There are 2 functions involved here:

1.  template <typename U> void operator<< (A<int> &, const U &);
    which is generated by the compiler when instantiating A<int>.

2.  template<typename T> void operator<< (A<T> &, const B &);

So you have ambiguity here.

Note that the template friend does not mean this function:

    template <typename T, typename U> void operator<< (A<T> &, const U &);