Подтвердить что ты не робот

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

Является ли это ошибкой компилятора?

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

Ответ 1

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

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

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

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


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

Ответ 2

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

Для выражения ++bar выполняется два поиска по именам.

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

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

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

Ответ 3

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

void f(int);

struct C {
void f(const C&);
void g() {
    f(3); // error: f(const C&) can't be called with argument 3
};