Еще один способ сделать это:
#include <algorithm>
#include <iterator>
#include <iostream>
template<typename>
struct enum_traits { static constexpr void* values = nullptr; };
namespace detail
{
template<typename T>
constexpr bool is_value_of(int, void*) { return false; }
template<typename T, typename U>
constexpr bool is_value_of(int v, U)
{
using std::begin; using std::end;
return std::find_if(begin(enum_traits<T>::values), end(enum_traits<T>::values),
[=](auto value){ return value == static_cast<T>(v); }
) != end(enum_traits<T>::values);
}
}
template<typename T>
constexpr bool is_value_of(int v)
{ return detail::is_value_of<T>(v, decltype(enum_traits<T>::values) { }); }
////////////////////
enum Abc { A = 4, B = 8, C = 12 };
template<>
struct enum_traits<Abc> { static constexpr auto values = { A, B, C }; };
decltype(enum_traits<Abc>::values) enum_traits<Abc>::values;
enum class Def { D = 1, E = 3, F = 5 };
int main()
{
std::cout << "Abc:";
for(int i = 0; i < 10; ++i)
if(is_value_of<Abc>(i)) std::cout << " " << i;
std::cout << std::endl;
std::cout << "Def:";
for(int i = 0; i < 10; ++i)
if(is_value_of<Def>(i)) std::cout << " " << i;
std::cout << std::endl;
return 0;
}
"Уродливая" часть этого подхода ИМХО должна определить:
decltype(enum_traits<Abc>::values) enum_traits<Abc>::values
Если вы не против макросов, вы можете обернуть его внутри макроса:
#define REGISTER_ENUM_VALUES(name, ...) \
template<> struct enum_traits<name> { static constexpr auto values = { __VA_ARGS__ }; }; \
decltype(enum_traits<name>::values) enum_traits<name>::values;