Несоответствие компилятора имени класса
Рассмотрим этот код:
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
? Или я неправильно интерпретирую цитату стандартов?
Ответы
Ответ 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, похоже, верит в это.: -)