Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Consider following code snippet with C++20 using-enum-declaration:

namespace A { enum A {}; };

using namespace A;
using enum A;

gcc-trunk rejects it with:

<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;
      |            ^

However, msvc accepts it. Interestingly, if I add a namespace qualifier for enum A:

namespace A { enum A {}; };

using namespace A;
using enum A::A;

gcc accepts it this time, but msvc rejects it with:

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

Which compiler is right?

like image 254
康桓瑋 Avatar asked Apr 14 '21 17:04

康桓瑋


People also ask

Which is an example of enum declaration?

Following is an example of enum declaration. // The name of enumeration is "flag" and the constant // are the values of the flag. By default, the values // of the constants are as follows: // constant1 = 0, constant2 = 1, constant3 = 2 and // so on. enum flag {constant1, constant2, constant3, ....... };

How to declare enumeration types in C and C++?

Check out our Data Structures in C course to start learning today. The keyword ‘enum’ is used to declare new enumeration types in C and C++. Following is an example of enum declaration. // The name of enumeration is "flag" and the constant // are the values of the flag.

What is the use of enum in C++?

It is mainly used to assign names to integral constants, the names make a program easy to read and maintain. The keyword ‘enum’ is used to declare new enumeration types in C and C++. Following is an example of enum declaration. // The name of enumeration is "flag" and the constant // are the values of the flag.

What are the requirements for ENUM names?

The value assigned to enum names must be some integeral constant, i.e., the value must be in range from minimum possible integer value to maximum possible integer value. 5. All enum constants must be unique in their scope. For example, the following program fails in compilation.


Video Answer


2 Answers

gcc is wrong here (submitted 100'084).

The grammar for using enum A; is from [enum.udecl]:

using-enum-declaration:

    using elaborated-enum-specifier ;

Lookup for such a thing is defined in [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]).

An elaborated-enum-specifier is one kind of elaborated-type-specifier, so we do type-only lookup. Which is defined as, in [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.

This means that when we look up A, while we find both the enum A and the namespace A, because our lookup is type-only we only consider the former and not the latter. As a result, we only have a single candidate and that's the one our lookup finds. There is no ambiguity.

like image 95
Barry Avatar answered Oct 18 '22 23:10

Barry


MSVC is correct here. The first case is a type-only lookup (as it’s considered an elaborated type specifier), so it ignores the namespace and finds the enumeration via the using-directive. In the second case, the following :: allows namespaces to be found, so it’s ambiguous.

like image 5
Davis Herring Avatar answered Oct 18 '22 21:10

Davis Herring