Оператор в области имен, скрывающий другого в глобальной области.

Это ошибка компилятора?

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);

12

Решение

Нет, это не ошибка. Рассматриваются три параллельных набора операторов. Члены, операторы, не являющиеся членами, и встроенные функции.

Не являющиеся членами ищутся обычным неквалифицированным поиском + ADL, игнорируя все функции-члены класса. Следовательно, глобальный оператор скрыт лексическим более близким оператором (и промежуточная функция-член не скрыла бы других не-членов).

Обратите внимание, что разрешение перегрузки имеет место после поиск имени1; в твоем случае имя operator++ был найден, но нет соответствующей перегрузки.

Если бы Bar был объявлен глобально, и / или другой оператор в пространстве имен asdf, ADL (в первом случае) или обычный неквалифицированный поиск (в последнем случае) привел бы оператора в.


1: Overload resolution (...) takes place after name lookup has succeeded. (Стандарт C ++)

13

Другие решения

Нет, это не ошибка компилятора.

Есть два поиска имени, которые выполняются для выражения ++bar,

  • При обычном поиске по имени выполняется поиск по окружающим областям и пространствам имен, пока не будет найден первый возникновение operator++, Этот поиск работает наизнанку, поэтому глобальное пространство имен ищется последним. При поиске операторных функций функции-члены обрабатываются отдельно (и не останавливают этот поиск).
  • Зависимый от аргумента поиск запускается следующим и ищет дополнительные классы и пространства имен, но только те, которые связаны с аргументами функции (operator++ в этом случае).

В примере в вопросе нормальный поиск находит asdf::operator++ и перестает смотреть.
Зависимый от аргумента поиск только добавляет asdf пространство имен для мест поиска, потому что это связанное пространство имен для enum Bar, По этой причине глобальный operator++ не может быть найден.

Вы можете сделать глобальный operator++ найти с помощью объявления об использовании в пространстве имен asdf,

7

Перегрузка распространяется только на определенные имена в том же объеме. Как только компилятор находит подходящее имя, он не просматривается во внешних областях, даже если найденное им имя относится к чему-то, что не может быть использовано. Это не имеет ничего общего с операторами; если код использует имя функции так же, как и оператор ++, он получит ту же ошибку. Например:

void f(int);

struct C {
void f(const C&);
void g() {
f(3); // error: f(const C&) can't be called with argument 3
};
1
По вопросам рекламы [email protected]