注入 class 名称编译器差异

Injected class name compiler discrepancy

考虑这段代码:

struct foo{};

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

我希望它的格式正确,根据 [class]/2 中的规则声明类型 foo 的变量(N4140,强调我的):

A class-name is inserted into the scope in which it is declared immediately after the class-name is seen. The class-name is also inserted into the scope of the class itself; this is known as the injected-class-name. For purposes of access checking, the injected-class-name is treated as if it were a public member name.

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;

无论注入的 class 名称的嵌套有多深,以上内容都适用,例如foo::foo::foo::foo.

是否存在强制将构造函数解释为该上下文中的构造函数的规则,或者这是一个gcc 错误?还是我对标准引用的解释不正确?

我认为这是language defect #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 似乎是这么认为的。 :-)

相关,但不是答案:GCC 人员确切地 讨论了这个 for years and figured that it should not be accepted. They explicitly made this an error in GCC 4.5 and newer - in 4.4.7 它被接受了。

顺便说一句:在调查此类内容时,您可能想使用 Clang 的 -Weverything 而不是 -Wall -pedantic

在这种情况下,clang 似乎是错误的。我正在寻找的相关例外是 [class.qual]/2:

2 In a lookup in which function names are not ignored and the nested-name-specifier nominates a class C:

  • (2.1) if the name specified after the nested-name-specifier, when looked up in C, is the injected-class-name of C, or

  • [...]

the name is instead considered to name the constructor of class 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 中有一个 existing bug