使用枚举声明的 C++20 模糊名称查找

Ambiguous name lookup with C++20 using-enum-declaration

考虑使用 C++20 using-enum-declaration 的以下代码片段:

namespace A { enum A {}; };

using namespace A;
using enum A;

gcc-trunk rejects 它与:

<source>:4:12: error: reference to 'A' is ambiguous
    4 | using enum A;
      |            ^
<source>:1:20: note: candidates are: 'enum A::A'
    1 | namespace A { enum A {}; };
      |                    ^
<source>:1:11: note:                 'namespace A { }'
    1 | namespace A { enum A {}; };
      |           ^
<source>:4:12: error: 'A' has not been declared
    4 | using enum A;
      |            ^

但是,msvc 接受它。有趣的是,如果我为 enum A:

添加命名空间限定符
namespace A { enum A {}; };

using namespace A;
using enum A::A;

gcc 这次接受 它,但是 msvc rejects 它与:

<source>(4): error C2872: 'A': ambiguous symbol
<source>(1): note: could be 'A'
<source>(1): note: or       'A::A'

哪个编译器是正确的?

这里gcc错了(已提交100'084)。

using enum A; 的语法来自 [enum.udecl]:

using-enum-declaration:

    using elaborated-enum-specifier ;

[basic.lookup.elab]:

中定义了此类内容的查找

If the class-key or enum keyword in an elaborated-type-specifier is followed by an identifier that is not followed by ​::​, lookup for the identifier is type-only ([basic.lookup.general]).

一个 elaborated-enum-specifier 是一种 elaborated-type-specifier,所以我们只进行类型查找。定义为 [basic.lookup.general]/4:

However, if a lookup is type-only, only declarations of types and templates whose specializations are types are considered; furthermore, if declarations of a typedef-name and of the type to which it refers are found, the declaration of the typedef-name is discarded instead of the type declaration.

这意味着当我们查找 A 时,我们同时找到 enum Anamespace A,因为我们的查找是仅类型的,我们只考虑前者而不是前者后者。结果,我们只有一个候选者,这就是我们的查找找到的那个。没有歧义。

这里的 MSVC 是正确的。第一种情况是仅类型查找(因为它被认为是详细的类型说明符),因此它忽略命名空间并通过 using-directive 查找枚举。第二种情况,下面的::允许找到命名空间,所以有歧义。