3. Rationale

3.1. Consistency

enumclasses, as well as plain old enums, are not classes - they seem to be closer to namespaces consisting of staticconstexpr inline variables. The familiar using syntax that works for namespaces should therefore apply to them as well, in some fashion.

3.2. Better Identifiers

The introduction of this feature would allow better naming of enums. Currently, enums are named with as short an identifier as possible, often to the point of absurdity, when they are reduced to completely nondescriptive abbreviations that only hint at their proper meaning. (Just what does zfqc::add_op really mean?)

With this feature, identifiers become available to unqualified lookup in local contexts where their source is obvious, giving control of lookup style back to the user of the enum, instead of baking name semantics into the type of the enum.

3.3. Evidence of Need

Anecdotally, 100% of people the authors have shown this to (~30) at CppCon have displayed a very enthusiastic response, with frequent comments of "I’d use enum classes but they are too verbose, this solves my problem!"

4. Proposal

4.1. Syntax: usingenumIDENTIFIER

We propose the addition of a new usingenum statement:

usingenumIDENTIFIER;

The above statement introduces the members of the enumeration IDENTIFIER into the local namespace, thus enabling lookup without qualification. As usual, a name lookup ambiguity makes the program ill-formed (diagnostic required).

4.2. Syntax: usingENUM_ID::IDENTIFIER

We propose to allow the syntax of

usingENUM_ID::IDENTIFIER

to introduce the IDENTIFIER into the local namespace, aliasing ENUM_ID::IDENTIFIER.

This would mirror the current syntax for introducing namespaced names into the current scope.

Note: this does not conflict with [P0945R0], because that paper only deals with the syntax usingname=id-expression, which duplicates the enumerator name.

5. Examples

5.1. Strongly typed enums with global identifiers

This proposal lets you make strongly-typed enums still export their identifiers to namespace scope, therefore behaving like the old enums in that respect:

6. Frequently Asked Questions

6.1. Has this been implemented?

Yes. The author has an implementation in clang. It has not been reviewed or released yet, however. There do not seem to be major issues with implementation.

6.2. Can I do this with unscoped enums?

Yes. The motivation for that is the pattern

classfoo{enumbar{A,B,C};};

which was superceeded by scoped enums. With the feature this paper proposes one can bring A, B and C into the local scope by invoking:

usingenumfoo::bar;

6.3. Are you proposing mirroring the namespace alias syntax as well?

No. We already have a way to do that, and it looks like this:

usingmy_alias=my::name_space::enum_name;

In addition, [P0945R0] proposes deprecating namespace aliases in favor of generalized usingname=id_expression, so doing this would go counter the current movement of the standard.

6.4. Why not allow usingenumstruct/classENUM_ID;?

Because would have been a needless complication and would introduce another layer of "struct and class don’t match" linter errors that current classes and structs already have with forward declarations.

6.5. Why propose usingENUM_ID::IDENTIFIER at all?

The reason is "DRY" - don’t repeat yourself - one is forced to repeat the name of the enumerator. That said, the authors are perfectly willing to throw this part of the paper out if the usingenumENUM_ID piece gets consensus and this is the stumbling block.

7. Proposed Wording

7.1. Preface

The authors are new at this, and welcome suggestions for wording.

The intention is to effectively mirror the wording for namespaces from [namespace.udir], and pare it down to only things that apply to enumerators.

All wording is relative to the working draft of the ISO/IEC IS 14882: N4765.

A using-enum-directive shall not appear in class scope, but may appear in namespace scope or in block scope. The optional attribute-specifier-seq appertains to the using-enum-directive. The enum-name in a using-enum-directive shall name a scoped enumeration or an unscoped enumeration.

A using-enum-directive specifies that the enumerators in the nominated scoped enumeration or unscoped enumeration can be used in the scope in which the using-enum-directive appears after the using-enum-directive. During unqualified name lookup ([basic.lookup.unqual]), the names appear as if they were declared in the scope where the using-enum-directive appears.

A using-enum-directive does not add any members to the declarative region in which it appears. [ Example:

7.3. Changes required to add usingENUM_ID::IDENTIFIER;

In chapter [namespace.udecl], remove:

A using-declaration shall not name a scoped enumerator.

Then add:

A using-declaration that names a scoped or unscoped enumerator shall become a synonim for that enumerator in the using-declaration’s declarative region. [ Note: this is equivalent to declaring that enumerator in the using-declaration’s declarative region. — end note]

8. Acknowledgements

The authors would like to thank Marcel Ebmer and Lisa Lippincott for early feedback, and the members of the BSI C++ WG for further feedback, especially Graham Haynes and Barry Revzin. Even further feedback was provided by Tomas Puverle, who encouraged us to extend it to enums, and Dan Saks for the permission to include a quotation from him.