Created
January 21, 2017 18:05
-
-
Save hutorny/5d8b1caac02710b9549be213d7d436e5 to your computer and use it in GitHub Desktop.
Zero-dependency allocation-free mapping enum values to names for C++11
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** zero-dependency allocation-free mapping enum values to names */ | |
namespace enumnames { | |
typedef const char* (*name)(); | |
bool match(const char*, const char*) noexcept; /* to be provided by the user */ | |
template<typename T, T K, name V> | |
struct tuple { | |
typedef T key_t; | |
static constexpr T key = K; | |
static constexpr name val = V; | |
}; | |
template<typename ... L> | |
struct map; | |
template<typename L> | |
struct map<L> { | |
static constexpr typename L::key_t get(const char*) noexcept { | |
return L::key; /* always returning last element */ | |
} | |
static constexpr const char* get(typename L::key_t key) noexcept { | |
return (L::val != nullptr) && (key == L::key) ? L::val() : ""; | |
} | |
}; | |
template<typename L, typename ... R> | |
struct map<L,R...> { | |
static typename L::key_t get(const char* val) noexcept { | |
static_assert(L::val != nullptr, "Only last element may have null name"); | |
return match(val, L::val()) ? L::key : map<R...>::get(val); | |
} | |
static constexpr const char* get(typename L::key_t key) noexcept { | |
return (key == L::key) ? L::val() : map<R...>::get(key); | |
} | |
}; | |
template<typename T, typename ... L> | |
struct names { | |
static T get(const char* nam) noexcept { | |
return M::get(nam); | |
} | |
static constexpr const char* get(T key) noexcept { | |
return M::get(key); | |
} | |
private: | |
typedef map<L...> M; | |
}; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* main.cpp - usage example for enumnames */ | |
#include <iostream> | |
#include <cstring> | |
#include "enumnames.hpp" | |
enum class fasion { | |
fancy, | |
classic, | |
sporty, | |
etno, | |
emo, | |
__last__ = emo, | |
__unknown__ = -1 | |
}; | |
/* needed for iterations only */ | |
static inline constexpr fasion operator+(fasion a, int b) noexcept { | |
return static_cast<fasion>(static_cast<int>(a) + b); | |
} | |
static inline constexpr int operator+(fasion a) noexcept { | |
return static_cast<int>(a); | |
} | |
#define NAME(s) static inline constexpr const char* s() noexcept {return #s;} | |
namespace name { | |
NAME(fancy) | |
NAME(classic) | |
NAME(sporty) | |
NAME(etno) | |
NAME(emo) | |
} | |
template<fasion K, enumnames::name V> | |
struct _ : enumnames::tuple<fasion, K,V> {}; | |
typedef enumnames::names<fasion, | |
_<fasion::fancy, name::fancy>, | |
_<fasion::classic, name::classic>, | |
_<fasion::sporty, name::sporty>, | |
_<fasion::etno, name::etno>, | |
_<fasion::emo, name::emo>, | |
_<fasion::__unknown__, nullptr> | |
> fasion_names; | |
using namespace std; | |
int main() { | |
std::string str; | |
cout << "Enter fasion from the list:" << endl; | |
for(fasion i = fasion::fancy; i <= fasion::__last__; i = i+1) | |
cout << fasion_names::get(i) << endl; | |
cin >> str; | |
fasion selected = fasion_names::get(str.data()); | |
cout << "Selected :" << +selected << " (" << fasion_names::get(selected) << ")"; | |
} | |
namespace enumnames { | |
bool match(const char* a, const char* b) noexcept { | |
return strcasecmp(a,b) == 0; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I have changed so much your answer on StackOverflow that I am not sure you will accept the changes:
This gist provides a simple mapping based on C++ variadic templates.
This is a C++17-simplified version of the type-based map from the gist:
An example usage:
The
map<KeyValues...>
can be used in both directions:fasion_names::get(fasion::emo)
fasion_names::get("emo")
This example is available on godbolt.org
Result from
gcc-7 -std=c++1z -Ofast -S