Re: operator overloading
chris wrote:
Having recently switched to gcc 4.1.0, one of my
libraries has stopped compiling. I tracked this down
to a change in the rules used to resolve the best
match for overloaded operators. Before re-writing
everything, I'm trying to find out if this change is
fully standard compliant. Here is an example of the
problem:
| class y { };
| template <typename T>
| void bar( const T& x ) { std::cout << "nada\n"; }
| template <typename T>
| void humbug( const T& x ) { bar(x); }
| void bar( int ) { std::cout << "int\n"; }
| void bar( y ) { std::cout << "y\n"; }
Because of the (strange) difference in overloading behaviour
between fundamental types and classes, humbug(5) only searches
before the template declaration for matches and so prints
"nada", but humbug( y() ) will also search after the
declaration and so prints "y".
It's not really a difference in overloading behavior; it's a
difference as to where the types are defined. (Of course, that
doesn't make it any less strange, intuitively:-)). Basically,
in the call to bar in humbug, bar is a dependent name, so
follows the rules of dependent name lookup, which means that
"the following sources are considered:
-- Declarations that are visible at the point of definition of
the template.
-- Declarations from namespaces associated with the types of
the function arguments both from the instantiation context
(14.6.4.1) and from the definition context."
In your example, the only declaration of bar that is visible at
the point of definition of the template is the template version
of bar. The two specializations are visible at the point of
instantiation, and will be found ONLY if the namespace which
contains them (the global namespace) is drawn into the search
because of one of the arguments. This happens with
humbug( y() ), because y is defined in the global namespace.
This doesn't work with humbug( 5 ), because int is defined
outside of all namespaces, so the compiler does not consider
definitions in the global namespace from the instantiation
context.
The former is new behaviour in 4.1.0 -- earlier version
printed "int" -- but seems to be prescribed by a defect report
to the standard. However, 4.1.0 is also different in how
overloading interacts with (multiple) namespace declarations.
If I modify the above slightly:
| namespace A {
| template <typename T>
| void bar( const T& x ) { std::cout << "nada\n"; }
| template <typename T>
| void humbug( const T& x ) { bar(x); }
| }
| namespace A {
| void bar( y ) { std::cout << "y\n"; }
| }
then a call to A::humbug( y() ) now prints "nada".
Same problem. Name lookup at the point of instantiation is
limited to ADL. And ADL only considers the namespaces on which
the arguments depend. So you get the only name visible at the
point of declaration.
I has always thought that namespaces were extensible
in the sense that
| namespace A { some code; }
| namespace A { some more code; }
is equivalent to
| namespace A { some code; some more code; }
It is, and putting the above in a single namespace block, in the
same order, shouldn't change anything.
but this is clearly not the case for resolving operator
overloading in gcc 4.1.0 . Does anybody know if this is
the correct behaviour?
The behavior of g++ is correct. Your interpretation of what is
happening isn't.
--
James Kanze GABI Software
Conseils en informatique orient?e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S?mard, 78210 St.-Cyr-l'?cole, France, +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]