Reputation: 2796
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
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
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