Is there a way to initialize a container (e.g. std::unordered_set<char>
) with the enumerators of an enum class
?
I have this class:
#include <iostream>
#include <unordered_set>
class Foo
{
public:
inline static const std::unordered_set<char> chars_for_drawing { '/', '\\', '|', '-' };
};
int main( )
{
for ( const char ch : Foo::chars_for_drawing )
{
std::cout << ch << ' ';
}
}
But I want the chars_for_drawing
set to be initialized with the enumerators:
#include <iostream>
#include <unordered_set>
class Foo
{
public:
enum class AllowedChars : char
{
ForwardSlash = '/',
BackSlash = '\\',
VerticalSlash = '|',
Dash = '-'
};
// inline static const std::unordered_set<char> chars_for_drawing { '/', '\\', '|', '-' }; // not like this
inline static const std::unordered_set<char> chars_for_drawing {
static_cast<char>( AllowedChars::ForwardSlash ),
static_cast<char>( AllowedChars::BackSlash ),
static_cast<char>( AllowedChars::VerticalSlash ),
static_cast<char>( AllowedChars::Dash )
};
};
int main( )
{
for ( const char ch : Foo::chars_for_drawing )
{
std::cout << ch << ' ';
}
}
As can be seen, the second approach is a bit messy. Is there way to iterate over the enumerators and assign them to the unordered_set
? Maybe by using a lambda?
No there is no straightforward way. Something one often forgets: The range of the enums values is determined by its underlying type. The enumerators are just some named constants. Your enum:
enum class AllowedChars : char
{
ForwardSlash = '/',
BackSlash = '\\',
VerticalSlash = '|',
Dash = '-'
};
helps for iterating as much as a
struct {
char value;
static const char ForwardSlash = '/';
static const char BackSlash = '\\';
static const char VerticalSlash = '|';
static const char Dash = '-';
};
does: Not at all.
Things are different when the enumerators have consecutive values and a hack that is used sometimes is to use a special enumerator to denote the "size":
enum class AllowedChars : char
{
ForwardSlash,
BackSlash,
VerticalSlash,
Dash,
SIZE
};
int main() {
for (int i=0;i< static_cast<int>(AllowedChars::SIZE); ++i){
std::cout << i;
}
}
That alone is a little silly, because the mapping to the actual characters is lost. However, it can be supplied by an array:
#include <iostream>
enum class AllowedCharNames : char
{
ForwardSlash,
BackSlash,
VerticalSlash,
Dash,
SIZE
};
char AllowedChars[] = {'/','\\','|','-'};
int main() {
std::cout << AllowedChars[static_cast<size_t>(AllowedCharNames::Dash)];
for (int i=0;i< static_cast<int>(AllowedCharNames::SIZE); ++i){
std::cout << AllowedChars[i];
}
}
TL;DR Reconsider if an enum is the right tool for the job. Enums are often overestimated for what they can really do. Sometimes not an enum is the better alternative.