지난 한 달 동안 나는 당신이 원하는 것을 할 수있는 방법 등을 찾고있었습니다. 당신은 내 github상의 예 -를 -including 전체 코드를 볼 수 있습니다
#define STD_ENUM_ENTRY_WITHOUT_VALUE__(ENUM, NAME) NAME,
#define STD_ENUM_ENTRY_WITHOUT_VALUE_(ENUM, NAME) STD_ENUM_ENTRY_WITHOUT_VALUE__(ENUM, NAME)
#define STD_ENUM_ENTRY_WITHOUT_VALUE(ENUM, SPLIT...) STD_ENUM_ENTRY_WITHOUT_VALUE_(ENUM, SPLIT)
#define STD_ENUM_ENTRY_WITH_VALUE__(ENUM, NAME, VALUE) NAME = VALUE,
#define STD_ENUM_ENTRY_WITH_VALUE_(ENUM, NAME, VALUE) STD_ENUM_ENTRY_WITH_VALUE__(ENUM, NAME, VALUE)
#define STD_ENUM_ENTRY_WITH_VALUE(ENUM, SPLIT...) STD_ENUM_ENTRY_WITH_VALUE_(ENUM, SPLIT)
#define FP_PP_ENUM_STD_ENTRY_1(ENUM, SPLIT...) STD_ENUM_ENTRY_WITHOUT_VALUE(ENUM, SPLIT)
#define FP_PP_ENUM_STD_ENTRY_2(ENUM, SPLIT...) STD_ENUM_ENTRY_WITH_VALUE(ENUM, SPLIT)
#define FP_PP_ENUM_STD_ENTRY__(N, ENUM, SPLIT...) FP_PP_ENUM_STD_ENTRY_##N(ENUM, SPLIT)
#define FP_PP_ENUM_STD_ENTRY_(N, ENUM, VALUE) FP_PP_ENUM_STD_ENTRY__(N, ENUM, FP_PP_EXPAND VALUE)
#define FP_PP_ENUM_STD_ENTRY(ENUM, VALUE) FP_PP_ENUM_STD_ENTRY_(FP_PP_NUM_ARGS VALUE, ENUM, VALUE)
#define FP_PP_ENUM_EXT_ENTRY_WITHOUT_VALUE__(ENUM, NAME) ::fp::enum_entry<ENUM>(ENUM::NAME, #NAME),
#define FP_PP_ENUM_EXT_ENTRY_WITHOUT_VALUE_(ENUM, NAME) FP_PP_ENUM_EXT_ENTRY_WITHOUT_VALUE__(ENUM, NAME)
#define FP_PP_ENUM_EXT_ENTRY_WITHOUT_VALUE(ENUM, SPLIT...) FP_PP_ENUM_EXT_ENTRY_WITHOUT_VALUE_(ENUM, SPLIT)
#define FP_PP_ENUM_EXT_ENTRY_WITH_VALUE__(ENUM, NAME, VALUE) ::fp::enum_entry<ENUM>(ENUM::NAME, #NAME),
#define FP_PP_ENUM_EXT_ENTRY_WITH_VALUE_(ENUM, NAME, VALUE) FP_PP_ENUM_EXT_ENTRY_WITH_VALUE__(ENUM, NAME, VALUE)
#define FP_PP_ENUM_EXT_ENTRY_WITH_VALUE(ENUM, SPLIT...) FP_PP_ENUM_EXT_ENTRY_WITH_VALUE_(ENUM, SPLIT)
#define FP_PP_ENUM_EXT_ENTRY_1(ENUM, SPLIT...) FP_PP_ENUM_EXT_ENTRY_WITHOUT_VALUE(ENUM, SPLIT)
#define FP_PP_ENUM_EXT_ENTRY_2(ENUM, SPLIT...) FP_PP_ENUM_EXT_ENTRY_WITH_VALUE(ENUM, SPLIT)
#define FP_PP_ENUM_EXT_ENTRY__(N, ENUM, SPLIT...) FP_PP_ENUM_EXT_ENTRY_##N(ENUM, SPLIT)
#define FP_PP_ENUM_EXT_ENTRY_(N, ENUM, VALUE) FP_PP_ENUM_EXT_ENTRY__(N, ENUM, FP_PP_EXPAND VALUE)
#define FP_PP_ENUM_EXT_ENTRY(ENUM, VALUE) FP_PP_ENUM_EXT_ENTRY_(FP_PP_NUM_ARGS VALUE, ENUM, VALUE)
#define DEFINE_EXT_ENUM(ENUM, ...) \
enum class ENUM { \
FP_PP_SEQ_FOR_EACH(FP_PP_ENUM_STD_ENTRY, ENUM, __VA_ARGS__) \
}; \
template<typename> \
struct enum_descriptor; \
\
template<> \
struct enum_descriptor<ENUM> { \
public: \
using enum_type = ENUM; \
using entry_type = ::fp::enum_entry<enum_type>; \
using this_type = enum_descriptor<enum_type>; \
using const_iterator = entry_type const *; \
using const_reverse_iterator = std::reverse_iterator<const_iterator>; \
using size_type = std::size_t; \
private: \
constexpr static std::size_t Size = FP_PP_NUM_ARGS(__VA_ARGS__); \
using container_type = std::array<entry_type, Size>; \
\
constexpr static container_type const _entries \
{ \
{ \
FP_PP_SEQ_FOR_EACH(FP_PP_ENUM_EXT_ENTRY, ENUM, __VA_ARGS__) \
} \
}; \
\
template<std::size_t... Is > \
constexpr static char const * name_of_impl(enum_type v, ::fp::indices<Is...>) { \
using std::get; \
return ::fp::enum_helper<enum_type>::get_name(v, get<Is>(_entries)...); \
} \
\
template<std::size_t... Is > \
constexpr static enum_type value_of_impl(char const * n, ::fp::indices<Is...>) { \
using std::get; \
return ::fp::enum_helper<enum_type>::get_value(n, get<Is>(_entries)...); \
} \
\
template<typename V, std::size_t... Is > \
static bool try_parse_impl(V val, enum_type & res, ::fp::indices<Is...>) { \
using std::get; \
return (::fp::enum_helper<enum_type>::is_valid_entry(val, get<Is>(_entries)...)) ? \
((res = static_cast<enum_type> (val)), true) \
: false; \
} \
\
template<typename V, std::size_t... Is > \
constexpr static enum_type parse_impl(V val, ::fp::indices<Is...>) { \
using std::get; \
return (::fp::enum_helper<enum_type>::parse(val, get<Is>(_entries)...)); \
} \
public: \
constexpr enum_descriptor() = default; \
enum_descriptor(enum_descriptor const &) = delete; \
enum_descriptor(enum_descriptor &&) = delete; \
\
constexpr static char const * name() noexcept { \
return #ENUM; \
} \
\
constexpr static char const * name_of(enum_type value) { \
return name_of_impl(value, ::fp::build_indices<Size>()); \
} \
\
constexpr static enum_type value_of(char const * name) { \
return value_of_impl(name, ::fp::build_indices<Size>()); \
} \
\
constexpr static size_type size() noexcept { \
return Size; \
} \
\
constexpr static const_iterator begin() { \
using std::get; \
return const_iterator(&get<0>(_entries)); \
} \
\
constexpr static const_iterator end() { \
using std::get; \
return const_iterator(&get<(Size - 1)>(_entries) + 1); \
} \
\
template<typename T, \
typename = typename std::enable_if<std::is_integral<T>::value>::type> \
static bool try_parse(T value, enum_type & res){ \
return try_parse_impl(value, res, ::fp::build_indices<Size>()); \
} \
\
template<typename T, \
typename = typename std::enable_if<std::is_integral<T>::value>::type> \
constexpr static enum_type parse(T value){ \
return parse_impl(value, ::fp::build_indices<Size>()); \
} \
}; \
template<> \
constexpr std::array<::fp::enum_entry<ENUM>, FP_PP_NUM_ARGS(__VA_ARGS__)> const enum_descriptor<ENUM>::_entries;
: 는 여기에 내가 무엇을 최대 온 것입니다.
이것이 예상 한대로 수행되지만, 기존 열거 형의 드롭 인 대체품으로 (직접) 사용할 수 없습니다.
DEFINE_EXT_ENUM(my_1st_enum, (fread, 3), (fwrite), (fflush, fread << 2));
DEFINE_EXT_ENUM(my_2nd_enum, (fopen), (fclose, 1));
마지막 한가지 : 다음 -Werr 플래그 GCC에이를 컴파일하려고하지 않습니다 때문에
것은, 자신에게 당신과 같이 정의되어야 지원하고자하는 열거 형을 코딩을 많이 저장하려면 컴파일이 오류가 발생합니다 (이유를 이해하지만 현재 해결 방법을 알지 못합니다).
편집 : 귀하의 예제를 바탕으로
이 당신이 내 DEFINE_EXT_ENUM 사용하여 어떻게 할 것입니다 : 내가 열거 형의 래퍼 (안 C 지원을 생성하는이 추악한 매크로를 썼다
#include "enum_pp_def.hpp"
#include <cassert>
#include <iostream>
DEFINE_EXT_ENUM(turn, (right,1), (left,2));
DEFINE_EXT_ENUM(hand, (right,1), (left,2));
using turn_descr = enum_descriptor<turn>;
using hand_descr = enum_descriptor<hand>;
/* 2 */
constexpr char const * foo(turn t) {
return (turn_descr::is_valid((int)t)) ? (turn::right == t) ? "right turn" : "left turn" : throw t;
}
constexpr char const * foo(hand h) {
return (hand_descr::is_valid((int)h)) ? (hand::right == h) ? "right hand" : "left hand" : throw h;
}
/* End 2 */
int main(int argc, char ** argv) {
turn t1 = turn_descr::parse(1); // 3.a OK
turn t2(turn::right); // 3b. OK
hand h1(hand::left); // 3c. OK
hand h2 = hand_descr::parse(2); // 3d. OK
assert(t1 == turn::right); // 4. OK
/* 8 */
switch(t1) {
case turn::right:
std::cout << "right turn" << std::endl;
break;
case turn::left:
std::cout << "left turn" << std::endl;
break;
}
/* End 8 */
std::cout << foo(hand::left) << std::endl;
std::cout << foo(turn::right) << std::endl;
constexpr turn t3 = turn_descr::parse(3) // throw at compile time
turn t4 = turn_descr::parse(3); // throw at runtime
}
일반 솔루션을 묻습니다. –
@MikeKinghan : "일반적인 솔루션"의 의미가 명확하지 않습니다. 내 솔루션이 제네릭이 아닌 이유는 무엇입니까? –
"일반 데이터 유형", "일반 알고리즘"(템플릿)에서와 같이 "일반". 인스턴스화 클래스 'C'가 컴파일 타임 등에 그러한 상수의 * i * th를 편리하게 전달할 수 있도록 임의의 정수형 'T'의 임의의 시퀀스 't0, .., tn'에 대해 인스턴스화 할 수있는 솔루션 'C'는't0, .., tn' 값만을 가정 할 수 있습니다. –