Reputation: 609
Is this a compiler-bug?
template <typename T>
T& operator++(T& t)
{
return t;
}
namespace asdf {
enum Foo { };
enum Bar { };
Foo& operator++(Foo& foo);
void fun()
{
Bar bar;
++bar;
}
} // end namespace asdf
int main()
{
return 0;
}
The GCC 4.7 error message is:
error: no match for 'operator++' in '++bar'
note: candidate is:
note: asdf::Foo& asdf::operator++(asdf::Foo&)
note: no known conversion for argument 1 from 'asdf::Bar' to 'asdf::Foo&'
It compiles if you comment out the line:
Foo& operator++(Foo& foo);
Upvotes: 13
Views: 886
Reputation: 15758
No, this is not a compiler bug.
There are two name-lookups that get performed for the expression ++bar
.
operator++
. This search works inside out, so the global namespace is searched last. When looking for operator functions, member-functions are treated separately (and don't stop this search).operator++
in this case).In the example in the question, the normal lookup finds asdf::operator++
and stops looking.
The argument-dependent lookup only adds the asdf
namespace to the places to search, because that is the associated namespace for enum Bar
. For that reason, the global operator++
can not be found.
You can make the global operator++
be found with a using declaration in namespace asdf
.
Upvotes: 8
Reputation: 76245
Overloading only applies to names defined in the same scope. Once the compiler finds a matching name it doesn't look in outer scopes, even if the name it found applies to something that can't be used. This has nothing to do with operators; if the code used a function name in the same way that it uses operator++ it would get the same error. For example:
void f(int);
struct C {
void f(const C&);
void g() {
f(3); // error: f(const C&) can't be called with argument 3
};
Upvotes: 1
Reputation: 506847
No that is not a bug. There are three parallel sets of operators considered. Members, non-member operators, and builtins.
The non-member ones are looked up by normal unqualified+ADL lookup, ignoring all class member functions. Hence the global operator is hidden by a lexical more closer one (and an intervening member function wouldn't have hidden other non-members).
Note that overload resolution takes place after name lookup1; in your case the name operator++
was found, but no appropriate overload.
If Bar had been declared globally, and/or the other operator in namespace asdf, ADL (in the former case) or ordinary unqualified lookup (in the latter case) would have dragged the operator in.
1: Overload resolution (...) takes place after name lookup has succeeded.
(C++ Standard)
Upvotes: 14