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

Несоответствие компилятора имени класса

Рассмотрим этот код:

struct foo{};

int main() {
    foo::foo a;
}

Я бы ожидал, что это будет хорошо сформировано, объявив переменную типа foo по правилу в [class]/2 (N4140, emphasis mine):

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

clang 3.6.0 согласен со мной, компилируя приведенный выше код без каких-либо предупреждений с помощью -Wall -pedantic.

gcc 5.2.0 отклоняется, предоставляя следующее сообщение об ошибке:

main.cpp: In function 'int main()':
main.cpp:5:5: error: 'foo::foo' names the constructor, not the type
   foo::foo a;

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

Есть ли правило, которое заставляет эту конструкцию интерпретироваться как конструктор в этом контексте или это ошибка gcc? Или я неправильно интерпретирую цитату стандартов?

4b9b3361

Ответ 1

Похоже, что clang в этом случае не так. Соответствующее исключение, которое я искал, находится в [class.qual]/2:

2 В поиске, в котором имена функций не игнорируются, а спецификатор вложенных имен назначает класс C:

  • (2.1) , если имя, указанное после вложенного имени-спецификатора, при поиске на C, представляет собой имя введенного класса C или

  • [...]

вместо этого имя считается именем конструктора класса C.

Стандарт имеет почти эквивалентный (ненормативный, очевидно) пример:

struct A { A(); };
struct B: public A { B(); };

A::A() { }
B::B() { }

B::A ba;// object of type A
A::A a;// error, A::A is not a type name
struct A::A a2;// object of type A

Однако clang действительно выдает правильную диагностику в этом случае:

error: qualified reference to 'A' is a constructor name rather than a type wherever a constructor can be declared

Возможно, clang интерпретирует строку In a lookup in which function names are not ignored как In a lookup in which a constructor declaration is valid, но это не кажется правильной интерпретацией.

Существует существующая ошибка для этого в clang bugzilla.

Ответ 2

Релевантный, но не ответ: люди GCC обсуждали именно этот в течение многих лет и полагали, что его не следует принимать. Они явно сделали ошибку в GCC 4.5 и новее - в 4.4.7 было принято.

BTW: Вы, вероятно, захотите использовать Clang -Weverything вместо -Wall -pedantic при исследовании таких материалов.

Ответ 3

Я думаю, что это тема языковой дефект # 147 который содержит этот пример

class B { };
class A: public B {
    A::B ab;       // B is the inherited injected B
    A::A aa;       // Error: A::A is the constructor
};

По крайней мере, gcc, похоже, верит в это.: -)