代码之家  ›  专栏  ›  技术社区  ›  余国良

如果在命名空间中声明的枚举是在命名空间之外定义的,那么它的枚举值在外部可见吗?

  •  1
  • 余国良  · 技术社区  · 1 年前

    我认为作用域枚举的限制性太强,所以我一直使用这种方法,但今天我发现它会导致CLANG中的命名污染。标准对能见度有什么规定?

    namespace E1_space {
        enum E1: int;
    }
    using E1 = E1_space::E1;  // or using E1_space::E1;
    enum E1_space::E1: int {
        Error
    };
    
    void foo() {
        Error; 
        // x86-64 GCC 14.2 error: 'Error' was not declared in this scope; did you mean 'P3::E1_space::Error'?
        // x64 MSVC v19.latest error C2065: 'Error': undeclared identifier
        // x86-64 CLANG 19.1.0 warning: expression result unused
    }
    
    1 回复  |  直到 1 年前
        1
  •  1
  •   StoryTeller - Unslander Monica    1 年前

    看起来语言本身(至少从C++23开始)有一个bug,这使得Clang的行为在技术上是合法的(无论 using 在场与否)。

    [dcl.enum]

    12 每个未作用域枚举器的名称也绑定在直接包含枚举说明符的作用域中。

    现在,您定义了一个未作用域的枚举,全局作用域似乎确实“立即包含枚举指定者”。这是因为 enum-specifier 是整个枚举定义:

     enum-specifier:
         enum-head { enumerator-listopt }
         enum-head { enumerator-list , } 
    

    然而,我觉得这完全疯了。虽然我在C++核心工作组中找不到这方面的问题,但我不认为这是一种预期行为。

    LLVM bug tracker ,Richard Smith(委员会成员和Clang维护者)似乎也同意所有编译器 但是 Clang做了明智的事情,Clang和语言本身都可能需要修改。


    经过一番思考,这可能是C++11之前的遗留措辞。您不能转发一次声明枚举;只有具有固定底层类型的枚举才能被前向声明,而这只是C++11之后的情况。因此,在C++03中,您无法将定义与第一个声明分开,因此上述[dcl.enum]/12处的措辞就足够了。