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

Действительно ли это код на С++?

У меня был следующий код, который был в основном,

class foo {
  public:
    void method();
};

void foo::foo::method() { }

Я случайно добавил дополнительный foo:: перед определением foo:: method. Этот код скомпилирован без предупреждения с помощью g++ (версия 4.2.3), но с ошибкой в ​​Visual Studio 2005. У меня не было пространства имен с именем foo.

Какой компилятор прав?

4b9b3361

Ответ 1

Если я правильно прочитал стандарт, g++ прав, а VS ошибочен.

ISO-IEC 14882-2003 (E), §9.2 Классы (pag.153): имя класса вставляется в область, в которой она объявляется сразу после того, как имя класса видел. Имя класса также вставляется в область самого класса; это известно как имя введенного класса. Для проверки доступа имя введенного класса рассматривается как имя публичного участника.

Следуя приведенным ниже замечаниям, особенно полезно сохранить следующее относительно фактических правил поиска имен:

ИСО-МЭК 14882-2003 (E), §3.4-3 Поиск имени (стр. 29): имя класса класса (раздел 9), введенное в класс, также считается член этого класса для скрытия имени и поиска.

Было бы странно, если бы это было не так, учитывая заключительную часть текста в 9.2. Но, как заметил Лэмб, это успокаивает нас тем, что действительно g++ делает правильную интерпретацию стандарта. Никаких вопросов не осталось.

Ответ 2

Krugar имеет правильный ответ здесь. Имя, которое находится каждый раз, является именем введенного класса.

Ниже приведен пример, который показывает по крайней мере одну причину, по которой компилятор добавляет имя введенного класса:

namespace NS
{
  class B
  {
  // injected name B    // #1
  public:
    void foo ();
  };

  int i;                // #2
}

class B                 // #3
{
public:
  void foo ();
};


int i;                  // #4

class A :: NS::B
{
public:
  void bar ()
  {
    ++i;           // Lookup for 'i' searches scope of
                   // 'A', then in base 'NS::B' and
                   // finally in '::'.  Finds #4

    B & b = *this; // Lookup for 'B' searches scope of 'A'
                   // then in base 'NS::B' and finds #1
                   // the injected name 'B'.

  }
};

Без введенного имени текущие правила поиска в конечном итоге достигнут охватывающей области "A" и будут найдены ":: B", а не "NS:: B". Поэтому нам нужно было бы использовать "NS:: B" всюду в A, когда мы хотели бы обратиться к базовому классу.

Другое место, в которое введены имена с именами, используется с шаблонами, где внутри шаблона класса введенное имя обеспечивает сопоставление между именем шаблона и типом:

template <typename T>
class A
{
// First injected name 'A<T>'
// Additional injected name 'A' maps to 'A<T>'

public:
  void foo ()
  {
    // '::A' here is the template name
    // 'A' is the type 'A<T>'
    // 'A<T>' is also the type 'A<T>'
  }
};

Ответ 3

Comeau online принимает его без каких-либо hickups, поэтому он либо действительный, либо второй баг в como, который я нашел почти за десять лет.

Ответ 4

Существует ли пространство имен foo в каком-то другом модуле, который вы включили (и вы просто не знали об этом)? В противном случае это неверно. Я не уверен, почему g++ допустил это.