Разрешение перегрузки: как это не двусмысленно?

Предположим, у нас есть этот код, скопированный из отдельного вопроса:

namespace x 
{
    void f()
    {
    }

    class C 
    {
        void f() 
        {
            using x::f;
            f();         // <==
        }
    };
}

Имя f в указанной строке однозначно относится к x::f (по крайней мере, согласно и gcc, и clang). Почему в данном случае x::f предпочтительнее x::C::f? Разве это не должно быть двусмысленно, поскольку видны оба имени?


person Barry    schedule 05.12.2014    source источник


Ответы (3)


Потому что объявление using вводит x::f в область действия f, которая уже, чем у C. Неквалифицированный поиск рассматривает локальную область действия блока, находит совпадение и останавливается перед рассмотрением более широкой области действия класса. Поиск, зависящий от аргументов, отсутствует, поскольку аргументы функции отсутствуют, поэтому дальнейшие области действия не рассматриваются.

person Mike Seymour    schedule 05.12.2014

Ответ @MikeSeymour точен; вот соответствующие стандартные цитаты (С++ 11, акцент мой):

13.3.1.1.1/3:

В неквалифицированных вызовах функций имя не уточняется оператором -> или . и имеет более общую форму primary-expression. Имя просматривается в контексте вызова функции после обычного правила поиска имени в вызовах функций (3.4). Объявления функций, найденные этим поиском, составляют набор функций-кандидатов. Из-за правил поиска имен набор функций-кандидатов состоит (1) полностью из функций, не являющихся членами, или (2) полностью из функций-членов некоторого класса T. ...

3.4.1/1:

Во всех случаях, перечисленных в 3.4.1, области действия ищут объявления в порядке, указанном в каждой из соответствующих категорий; поиск имени завершается, как только для имени найдено объявление. Если объявление не найдено, программа неправильно сформирована.

3.4.1/8

Имя, используемое в определении функции-члена (9.3) класса X после идентификатора-декларатора функции ... должно быть объявлено одним из следующих способов:

  • до его использования в блоке, в котором он используется, или во вмещающем блоке (6.3), или
  • должен быть членом класса X или быть членом базового класса X (10.2), или
  • ...

Из версии 3.4.1/8 мы видим, что объявление имени f (например, объявление using x::f;) в блоке, в котором оно используется, указано раньше, чем f, как член класса C. В соответствии с 3.4.1/1 выбирается более ранний, поэтому весь поиск разрешается в x::f, представленный объявлением using.

person Angew is no longer proud of SO    schedule 05.12.2014

Я думаю, что эти цитаты из стандарта C++ будут актуальны:

Из стандарта С++ (7.3.3 Объявление использования)

13 Поскольку использование-объявления является объявлением, ограничения на объявления с тем же именем в той же области объявлений (3.3) также применяются к использованиям-объявлений.

И (3.3.7 Объем класса)

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

person Vlad from Moscow    schedule 05.12.2014