Skip to content

Instantly share code, notes, and snippets.

@Manu343726
Last active October 31, 2017 09:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Manu343726/b0cab31364b5f2fdc2437ca1d460305f to your computer and use it in GitHub Desktop.
Save Manu343726/b0cab31364b5f2fdc2437ca1d460305f to your computer and use it in GitHub Desktop.
C++11 introspectable "enums"
#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
@Manu343726
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment