为何使用using namespace后未触发枚举符ERR_FILE_ACCESS重定义冲突?
问题场景
编译报错的代码(test.cpp)
enum { ERR_FILE_ACCESS = 1, ERR_WHATEVER }; enum ERR : unsigned int { ERR_FILE_ACCESS = 5, ERR_FILE_FORMAT = 6 }; int main(int, char**) { return 0; }
这段代码编译时会报错:redefinition of enumerator 'ERR_FILE_ACCESS',原因是全局作用域的匿名枚举和具名枚举ERR都定义了同名的ERR_FILE_ACCESS。
可正常编译的代码(test2.cpp)
enum { ERR_FILE_ACCESS = 1, ERR_FILE_FORMAT, ERR_WHATEVER }; namespace Internal { enum ERR : unsigned int { ERR_FILE_ACCESS = 5, ERR_FILE_FORMAT = 6 }; } using namespace Internal; int main(int, char**) { return 0; }
这段代码将具名枚举ERR放入Internal命名空间,即使添加了using namespace Internal;语句,依然可以正常编译,不会出现名称冲突。
疑问
为什么使用using namespace Internal;后,两个ERR_FILE_ACCESS没有产生编译冲突?
核心原因解析
匿名枚举的成员作用域
全局作用域下的匿名枚举,其所有枚举成员会直接暴露在当前作用域(这里是全局),也就是说ERR_FILE_ACCESS是一个全局名称。具名枚举的成员作用域
C++中,具名枚举(如enum ERR)的成员默认被限定在枚举类型自身的作用域内,而不是所属的命名空间。即使通过using namespace Internal;将命名空间引入当前作用域,也只是把Internal里的枚举类型ERR暴露出来,并不会把ERR内部的成员直接放到全局作用域里。冲突触发的条件
只有当代码中直接引用ERR_FILE_ACCESS这个名称时,编译器才会进行名称查找:此时全局的ERR_FILE_ACCESS和Internal::ERR::ERR_FILE_ACCESS会被视为不同作用域的同名标识符,触发歧义报错。而test2.cpp中并没有使用这个有歧义的名称,所以编译器不会主动检查冲突。
对比test.cpp的情况:具名枚举ERR处于全局作用域,它的成员会直接暴露在全局(遵循C++早期的枚举成员作用域规则),因此和匿名枚举的全局成员直接重名,编译阶段就会报错。
内容的提问来源于stack exchange,提问作者albert

