Функция статического члена класса, выбранная по глобальной функции с тем же именем?

Сомнение произошло здесь


int g() {
   cout << "In function g()" << endl;
   return 0;
}

class X {
public:
  static int g() {
     cout << "In static member function X::g()" << endl;
     return 1;
  }
};

class Y: public X {
   public:
  static int i;
};

int Y::i = g();   

изначально я хотя бы потому, что, поскольку разрешение символа происходит от внутренней самой области видимости до внешней самой области видимости, поэтому будет вызываться x:: g()., но затем я внимательно заметил код

int Y::i = g();

как мы можем получить доступ к X:: g() без namescope?
И область, в которой лежит это утверждение, должна быть глобальной, а не Y:: или X::, поэтому разрешение символа должно давать глобальную версию функции g()?

Ответ 1

Примечание. Я думаю, что мой предыдущий ответ был неправильным. Его не Koenig Lookup i.e Поиск зависимых от аргументов имен (ADL). Поэтому я удалил свой (ранее) ответ, так как нашел соответствующий раздел из Стандарта, который отвечает на ваш вопрос.

Ваш код непосредственно из раздела §9.4/2 стандарта С++ 03.

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

Затем он приводит этот пример (который вы задали в вопросе)

[Example:

    int g();
    struct X {
        static int g();
    };
    struct Y : X {
        static int i;
    };
    int Y::i = g(); // equivalent to Y::g();

—end example]

Затем он говорит, что в § 9.4/3

Если неквалифицированный идентификатор (5.1) используется в определение статического членаследуя декларатору-идентификатору участников, и поиск имени (3.4.1) обнаруживает, что unqualified-id относится к статическому член, перечислитель или вложенный тип класс членов (или базового класса класса участников), unqualified-id преобразуется в expression-id, в котором Идентификатор имени вложенного имени указывает класс область, из которой ссылка.

Поскольку это определение только в определении статического члена, это означает, что Y::g() вызывается ТОЛЬКО в инициализации, а не в присваивании > :

//definition-cum-initialization
int Y::i = g(); // equivalent to Y::g();
int main()
{
   //assignment 
   Y::i = g(); // does not equivalent to Y::g(); it calls global g()
}

Смотрите вывод здесь: http://www.ideone.com/6KDMI

Давайте рассмотрим другой пример:

struct B{};

B f();

namespace NS 
{
   struct A { static B b;};
   B f();
}

//Definition cum Initialization
B NS::A::b = f();  //calls NS::f()
B b = f();         //calls global f()

int main() 
{
   //Assignment
   NS::A::b = f(); //calls global f()
   b = f();        //calls global f()
}

Смотрите полную демонстрацию здесь: http://www.ideone.com/53hoW

Ответ 2

Это потому, что вы используете int Y::i =..., обратите внимание на Y::. Поэтому на самом деле он ищет g() внутри Y, который X::g(), потому что Y выводит X.


Дополнение: Например, если вы поместите int i = g(); после int Y::i = g();, результат будет:

In static member function X::g()
In function g()

EDIT: точно - поиск по зависимым от аргумента. Я не мог вспомнить, как это называется в начале. Спасибо Nawaz ответить (:

EDIT2: ОК, Наваз нашел правильное объяснение, он в стандарте и, похоже, не "зависящий от аргументов поиск имени". Но логика по-прежнему абсолютно одинакова.