c++ 为什么编译器允许数据成员与类同名?

kzmpq1sx  于 2023-03-20  发布在  其他
关注(0)|答案(1)|浏览(98)

三个主要的编译器(gcc、clang、MSVC)很乐意编译下面的例子(godbolt):

struct Test
{
    // Member type `Test::Test` is supposedly introduced at this point
    // as an alias to `struct Test`, per https://eel.is/c++draft/class.pre#2

    // Shouldn't the following declaration be rejected since it redefines
    // the name `Test` in the same scope?
    int     Test;

    // Doing the same explicitly would be a compilation error, as expected:
    // using   Probe = int;
    // int     Probe;
};

int main()
{
    Test    x;
    x.Test = 4;
}

**上面的例子是格式良好的吗?**为什么injected-class-name不使成员int Test;的声明无效?

查找规则[class.member.lookup]/6可能会使这个例子的格式不正确,并且没有诊断,这看起来是不相关的,因为在这个类完成之前,不会进行查找。还有哪些子句与这个例子相关?

8zzbczxx

8zzbczxx1#

根据C++17标准(12.2类成员)
18如果T是一个类的名称,那么下列每一个都应该有一个不同于T的名称:
(18.1)-类T的每个静态数据成员;
(18.2)-类T的每个成员函数[注:这个限制不适用于构造函数,它没有名字(15. 1)--结束注解] ;
(18.3)--类T中本身是一个类型的每一个成员;
(18.4)-T类的每个成员模板;
(18.5)-类T的每个成员的每个枚举数,它是一个无作用域的枚举类型;以及
(18.6)--每个匿名并集的每个成员都是类T的成员。
以及
19此外,如果类T有一个用户声明的构造函数(15.1),类T的每个非静态数据成员都应该有一个不同于T的名字。
因此,由于类没有用户声明的构造函数,因此其非静态数据成员Test可能与类名同名。
你甚至可以写

Test Test;
Test.Test = 4;

(It它似乎是允许与C兼容的,其中结构标记名称和数据成员的名称属于不同的名称空间。)
另一方面,如果将构造函数声明为例如

struct Test
{
    Test() = default;
    int     Test;
};

则编译器将发出错误。
一般来说,C++不允许在同一作用域中声明一个变量和一个函数。

相关问题