Last active
October 31, 2017 09:04
-
-
Save Manu343726/b0cab31364b5f2fdc2437ca1d460305f to your computer and use it in GitHub Desktop.
C++11 introspectable "enums"
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
#ifndef ENUMPP_HPP | |
#define ENUMPP_HPP | |
#include <initializer_list> | |
#include <utility> | |
#include <array> | |
#include <ostream> | |
template<typename T, std::size_t TotalValues> | |
struct Enum; | |
template<typename T> | |
struct EnumValue | |
{ | |
constexpr EnumValue(const char* name, T value) : | |
name{name}, | |
value{value} | |
{} | |
const char* const name; | |
const T value; | |
constexpr operator T() const | |
{ | |
return value; | |
} | |
}; | |
template<typename T> | |
constexpr bool operator==(const EnumValue<T>& lhs, const EnumValue<T>& rhs) | |
{ | |
return lhs.name == rhs.name; | |
} | |
template<typename T> | |
constexpr bool operator!=(const EnumValue<T>& lhs, const EnumValue<T>& rhs) | |
{ | |
return !(lhs.name == rhs.name); | |
} | |
template<typename T> | |
std::ostream& operator<<(std::ostream& os, const EnumValue<T>& value) | |
{ | |
return os << value.name; | |
} | |
template<typename T> | |
constexpr EnumValue<T> enumValue(const char* name, T value) | |
{ | |
return { name, value }; | |
} | |
namespace detail | |
{ | |
template<typename T, std::size_t TotalValues> | |
using ValuesArray = std::array<EnumValue<T>, TotalValues>; | |
template<typename T, std::size_t TotalValues> | |
struct FullValue : public EnumValue<T> | |
{ | |
constexpr FullValue(EnumValue<T> value, std::size_t index, const ValuesArray<T, TotalValues>& allValues) : | |
EnumValue<T>{value.name, value.value}, | |
index{index}, | |
allValues(allValues) | |
{} | |
const std::size_t index; | |
const ValuesArray<T, TotalValues> allValues; | |
}; | |
template<typename T, std::size_t TotalValues> | |
constexpr FullValue<T, TotalValues> findByName(const ValuesArray<T, TotalValues>& allValues, const char* name, std::size_t i = 0) | |
{ | |
return (allValues[i].name == name) ? FullValue<T, TotalValues>{allValues[i], i, allValues} : findByName(allValues, name, i + 1); | |
} | |
template<typename T, std::size_t TotalValues> | |
constexpr FullValue<T, TotalValues> findByValue(const ValuesArray<T, TotalValues>& allValues, T value, std::size_t i = 0) | |
{ | |
return (allValues[i].value == value) ? FullValue<T, TotalValues>{allValues[i], i, allValues} : findByValue(allValues, value, i + 1); | |
} | |
} | |
template<typename T, std::size_t TotalValues> | |
struct Enum | |
{ | |
using ValuesArray = detail::ValuesArray<T, TotalValues>; | |
using Value = detail::FullValue<T, TotalValues>; | |
template<typename... Values> | |
constexpr Enum(Values&&... values) : | |
values{std::forward<Values>(values)...} | |
{} | |
const ValuesArray values; | |
constexpr Value value(const char* name) const | |
{ | |
return detail::findByName(values, name); | |
} | |
constexpr Value value(T value) const | |
{ | |
return detail::findByValue(values, value); | |
} | |
constexpr Value operator[](const char* name) const | |
{ | |
return value(name); | |
} | |
}; | |
template<typename T, typename... Values> | |
constexpr Enum<T, sizeof...(Values)> enum_(Values&&... values) | |
{ | |
return { std::forward<Values>(values)... }; | |
} | |
#ifdef ENUMPP_MAIN | |
#include <iostream> | |
int main() | |
{ | |
constexpr auto myEnum = enum_<int>( | |
enumValue("hello", 1), | |
enumValue("world", 2) | |
); | |
constexpr auto hello = myEnum["hello"]; | |
using Type = std::integral_constant<int, hello.value>; | |
// Compile time error "array out of bounds" | |
// using WrongType = std::integral_constant<int, myEnum.value(42)>; | |
std::cout << hello << " (" << static_cast<int>(hello) << ")" << std::endl; | |
std::cout << "2 (" << myEnum.value(2) << ")" << std::endl; | |
} | |
#endif // ENUMPP_MAIN | |
#endif // ENUMPP_HPP |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
A working example http://coliru.stacked-crooked.com/a/94ef78c6a1c7923e