Это ошибка компилятора?
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;
}
Сообщение об ошибке GCC 4.7:
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&'
Он компилируется, если вы закомментируете строку:
Foo& operator++(Foo& foo);
Нет, это не ошибка. Рассматриваются три параллельных набора операторов. Члены, операторы, не являющиеся членами, и встроенные функции.
Не являющиеся членами ищутся обычным неквалифицированным поиском + ADL, игнорируя все функции-члены класса. Следовательно, глобальный оператор скрыт лексическим более близким оператором (и промежуточная функция-член не скрыла бы других не-членов).
Обратите внимание, что разрешение перегрузки имеет место после поиск имени1; в твоем случае имя operator++
был найден, но нет соответствующей перегрузки.
Если бы Bar был объявлен глобально, и / или другой оператор в пространстве имен asdf, ADL (в первом случае) или обычный неквалифицированный поиск (в последнем случае) привел бы оператора в.
1: Overload resolution (...) takes place after name lookup has succeeded.
(Стандарт C ++)
Нет, это не ошибка компилятора.
Есть два поиска имени, которые выполняются для выражения ++bar
,
operator++
, Этот поиск работает наизнанку, поэтому глобальное пространство имен ищется последним. При поиске операторных функций функции-члены обрабатываются отдельно (и не останавливают этот поиск).operator++
в этом случае).В примере в вопросе нормальный поиск находит asdf::operator++
и перестает смотреть.
Зависимый от аргумента поиск только добавляет asdf
пространство имен для мест поиска, потому что это связанное пространство имен для enum Bar
, По этой причине глобальный operator++
не может быть найден.
Вы можете сделать глобальный operator++
найти с помощью объявления об использовании в пространстве имен asdf
,
Перегрузка распространяется только на определенные имена в том же объеме. Как только компилятор находит подходящее имя, он не просматривается во внешних областях, даже если найденное им имя относится к чему-то, что не может быть использовано. Это не имеет ничего общего с операторами; если код использует имя функции так же, как и оператор ++, он получит ту же ошибку. Например:
void f(int);
struct C {
void f(const C&);
void g() {
f(3); // error: f(const C&) can't be called with argument 3
};