Tim
Tim

Reputation: 2796

Pulling C++ Enum Class Members Into the Global Namespace

Is there a using directive that imports the members of an enum class directly into the global namespace of a compilation unit?

We have:

enum Lexeme {....lots of names...};

bool Matches(int lookAhead, Lexeme lxm);

This is risky because users frequently forget that the first argument of Matches means "matches either" and write:

if (Matches(ADD,SUB)) ...

The C++ compiler is perfectly happy taking ADD as an int.

So I tried making Lexeme an enum class:

enum class Lexeme { ...}

This catches the error. But now my problem is that all the code that uses Lexeme constants must write the enum class name:

if (Matches(Lexeme::ADD,Lexeme::SUB)) ...

Is there a using directive, or another trick, to pull all of the Lexeme::* names into the current scope? Note, most tokens are used in a class (I get that properly qualifying the constants is one of the safety mechanisms of enum class).

Perhaps a better plan is to change Matches to MatchesAt, or something, to avoid the problem? But I wanted to know the rules for C++ and C++XX, at least.

What I tried:

This is related, but doesn't address the required enum class prefixes.

I also tried something like using foo::bar::Lexeme; but alas to no avail.

Upvotes: 0

Views: 692

Answers (2)

Javier Martín
Javier Martín

Reputation: 2605

On a different note, a way to avoid writing Lexeme:: every time would be just to create a shorter alias:

enum class Lexeme { /* lotsa names */ };
using L = Lexeme;

if (Matches(3, L::SUB)) //...

This works well if there is only one or two files where these values are used extensively, and other uses are sparse. I have just had to use a similar solution where I had a Parameter class that read things from XML. I have a enum class ElementType { INTEGER, BOOLEAN, /* etc*/ } and a parsing infrastructure. Within the parser file, I have:

using ET = ElementType;

template<ET et>
struct parser;

// Specializations for each ElementType
template<>
struct parser<ET::INTEGER> {
    using type = int;
    int parseSingle(const string& s) // ...
}

While outside this file I just have a few usages of ElementType::* constants and I use the full name of the enum class. Should this become too much of a burden, nothing prevents me from ading that alias to a different file.

Upvotes: 1

user7860670
user7860670

Reputation: 37549

You can make an integer wrapper class not convertible to anything else and make some constants out of it.

struct Lexeme
{
   private: int m_value;

   public: explicit constexpr Lexeme(int value) noexcept
   : m_value{value}
   {}
};

inline constexpr Lexeme const ADD{1};
inline constexpr Lexeme const SUB{2};

It would probably be a good idea to overload some operators for this class, at least equality and less than.

Upvotes: 1

Related Questions