为何编译器允许数据成员与类同名?语法合法性解析
关于C++注入类名与成员变量同名的标准合规性问题
三大主流编译器(gcc、clang、MSVC)均可正常编译以下代码:
struct Test { // 根据C++标准n4659的class#2,此时会引入成员类型`Test::Test`作为`struct Test`的别名 // 根据C++标准n4659的basic.lookup#3,以下声明为何未被视为同一作用域中的`Test`重定义? int Test; // 显式执行类似操作会触发编译错误,符合预期: // using Probe = int; // int Probe; }; int main() { Test x; x.Test = 4; }
问题:上述示例是否符合C++标准?若符合,原因是什么?为何注入类名不会使int Test;的声明无效?
这段代码完全符合C++标准,核心原因在于注入类名的特殊规则,具体解释如下:
注入类名的特殊属性
当定义struct Test时,C++标准会自动在类的作用域中注入一个名为Test的类型成员,它是该类自身类型的别名(即Test::Test等价于struct Test)。但这个注入的名字属于类型成员范畴,和变量、函数等非类型成员属于不同的分类。不同类别成员的共存规则
C++标准允许同一类作用域中存在同名但不同类别的成员——类型成员与非类型成员(如变量、函数)互不视为重定义。声明int Test;时,这是一个非类型成员变量,它会隐藏作用域中的注入类名,但二者不属于同一类别的声明,因此不会触发重定义错误。显式using声明的差异
注释中的using Probe = int;是显式在类作用域中声明的类型别名(属于类型成员),之后再声明int Probe;时,相当于试图将同一名字同时用作类型成员和非类型成员,这违反了普通类型别名的命名规则(注入类名是标准特例),因此会触发编译错误。名字查找的优先级
在类作用域中查找名字时,非类型成员的优先级高于注入类名。因此main函数中x.Test = 4;会正确匹配到成员变量,而非注入类名。
内容的提问来源于stack exchange,提问作者Igor G
相关产品推荐
相关产品推荐

