Существуют ли другие правила, касающиеся ADL или конфликтов имен в отношении перегруженных операторов?

Я думаю, что этот пример лучше всего иллюстрирует мой вопрос:

namespace N {

    class C {
    public:
        friend bool operator==(const C& c, const C& x) {
            return true;
        }
        friend bool f(const C& c, const C& x) {
            return true;
        }
    };

    class D {
    public:
        bool operator==(const D& x) {
            bool a = C{} == C{};      // this works
            return true;
        }
        bool f(const D& x) {
            bool a = f(C{}, C{});     // this does not work
            return true;
        }
    };
}

Я всегда рассматривал перегруженные операторы как функции, за исключением «синтаксиса вызова», если хотите. Я только что заметил вышеуказанную разницу в правилах ADL или поиска имени (я не знаю, в каких).

Может кто-нибудь объяснить, почему bool operator==(const C& c, const C& x) найдено, а bool f(const C& c, const C& x) нет?


person odinthenerd    schedule 11.06.2014    source источник
comment
Обратите внимание, что это скрытие, а не ADL, поскольку все находится в одном пространстве имен. ADL предназначен для поиска функции в дополнительных пространствах имен (в частности, пространствах имен, в которых определены типы параметров).   -  person T.C.    schedule 11.06.2014


Ответы (1)


Ваш D::f скрывает C::f; если вы переименуете последний в C::g и настроите вызов, тогда он будет работать нормально (показывая, что функция может быть найдена и доступна просто отлично).

Ваш код на самом деле не вызывает функции оператора напрямую, но язык делает это за вас. Следовательно, вы не используете имя операторной функции, поэтому скрытие имени не применяется.

Если вы напишете operator==(C{}, C{}) (вместо C{} == C{}), то увидите то же поведение, что и f(C{}, C{}) (демонстрация ).

Итак, когда вы говорите, что я всегда рассматривал перегруженные операторы как функции, за исключением «синтаксиса вызова», если хотите, вы уже попали в самую точку.


Вот некоторые стандарты для вас:

[C++11: 13.5/4]: Операторные функции обычно не вызываются напрямую; вместо этого они вызываются для оценки реализуемых ими операторов (13.5.1 — 13.5.7). Однако их можно вызывать явно, используя идентификатор-оператора-функции в качестве имени функции в синтаксисе вызова функции (5.2.2). [ Пример:

complex z = a.operator+(b); // complex z = a+b;
void* p = operator new(sizeof(int)*n);

—конец примера ]

[C++11: 3.3.7/4]: [..] 4) Имя, объявленное в функции-члене, скрывает объявление того же имени, область действия которого распространяется до конца класса функции-члена или за его пределы. [..]

[C++11: 3/4]: Имя — это использование идентификатора (2.11), идентификатора-оператора (13.5), идентификатора-оператора (13.5). .8), идентификатор-конверсии (12.3.2) или идентификатор-шаблона (14.2), который обозначает объект или метку ( 6.6.4, 6.1).

([квалифицированный] идентификатор функции-оператора здесь равен ::N::C::operator==.)

person Lightness Races in Orbit    schedule 11.06.2014