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

Вызов статического метода путем повторения имени объекта

У меня есть singleton:

struct foo {
  static foo& instance() {
    static foo f;
    return f;
  }
};

При повторной компоновке кода я закончил с этим утверждением "по ошибке":

foo::foo::instance()

Но мой компилятор (gcc 4.7) считается правильным. На самом деле даже foo::foo::foo::instance() компилируется. Почему?

4b9b3361

Ответ 1

Это происходит из-за "injected-name" — что означает, что foo - это имя класса, и в класс-область также вводится одно и то же имя "foo", поэтому ваш код работает. Он соответствует стандарту 100%.

Вот один интересный пример, который показывает преимущества этой функции:

namespace N
{
   //define a class here
   struct A 
   { 
       void f() { std::cout << "N::A" << std::endl; }
   };
}

namespace M
{
   //define another class with same name!
   struct A 
   { 
       void f() { std::cout << "M::A" << std::endl; }
   };

   struct B : N::A  //NOTE : deriving from N::A
   {
         B()
         {
            A a;
            a.f(); //what should it print?
         }
   };
}

Что нужно a.f() позвонить? Каков тип a? Это M::A или N::A? Ответ: N::A, not M::A.

Это связано с именем-инъекцией, N::A доступно внутри конструктора B без квалификации. Он также скрывает M::A, который остается вне области B. Если вы хотите использовать M::A, тогда вы должны написать M::A (или лучше ::M::A).

Ответ 2

Из-за [class]/2:

Имя класса вставляется в область, в которой объявляется сразу после просмотра имени класса. Имя класса также вставляется в область самого класса; это известно как имя введенного класса.

So foo::foo - это введенное имя класса, обозначающее foo.


На самом деле это немного сложнее: согласно [class.qual]/2, foo::foo сам по себе обозначает конструктор foo. Чтобы обозначить класс, ему должно предшествовать struct (что делает его уточненным-спецификатором типа) или следует за :: (что делает его вложенным именем-спецификатором - это ваш случай), или базовый-спецификатор (например, struct bar : foo::foo {};).

Ответ 3

Как указано в других ответах, причиной является инъекция имени. Для меня основным вариантом использования было бы следующее

struct B1 { void f(){} };
struct B2 { void f(){} };

struct D : B1, B2 { }

int main() {
    D obj; 
    obj.f(); 
}

В main вызов f неоднозначен и не будет компилироваться. Способ быть конкретным - это квалифицированный вызов, т.е.

obj.B1::f();