以前別のブログで書いた内容だが、一応Qiitaにも書いておこうかなと思った次第
概要
enumに応じてtype traitsを決定する
似たようなものとしてはこちらがあげられる
source
template<class Enum>
struct selector {
template<
bool Check,
size_t N,
Enum Select,
Enum First,
Enum ... Modes
>
struct resolve_select
{
static size_t const value = N - 1;
};
template<
size_t N,
Enum Select,
Enum First,
Enum ... Modes
>
struct resolve_select<false, N, Select, First, Modes ...> :
public resolve_select<First == Select, N + 1, Select, Modes ...>{};
template<
size_t N,
class Check,
class ... Remain>
struct resolve_type : public resolve_type<N - 1, Remain ... > {};
template<
class Check,
class ... Remain>
struct resolve_type<0, Check, Remain ...>
{
typedef Check type;
};
template<Enum ... Modes>
struct which {
template<Enum Select>
struct select {
template<class ... Types>
struct types {
typedef typename resolve_type<resolve_select<false, 0, Select, Modes ..., Select>::value, Types ...>::type type;
};
};
};
};
usage
こんな感じで使う
enum class Test {
hoge,
fuga,
};
template<Test Selector>
struct select {
using type = typename switch_types<Test>::which<hoge,fuga>::select<Selector>::template types<int,long>::type;
};
//select<hoge>::type -> int
//select<fuga>::type -> long
Boost.PPと組み合わせると
#define TEST
(( hoge, int )) \
(( fuga, long )) \
#define REFERENCE_PARAM_ENUM(params) \
BOOST_PP_TUPLE_ELEM(2,0,params)
#define REFERENCE_PARAM_CLASS(params) \
BOOST_PP_TUPLE_ELEM(2,1,params)
#define REFERENCE_FORMAT_ENUM(z,index,params) \
BOOST_PP_COMMA_IF(index) REFERENCE_PARAM_ENUM(BOOST_PP_SEQ_ELEM(index,params))
#define REFERENCE_FORMAT_CLASS(z,index,params) \
BOOST_PP_COMMA_IF(index) REFERENCE_PARAM_CLASS(BOOST_PP_SEQ_ELEM(index,params))
#define JOINER_GEN_STRUCT(name,enum_type,params) \
template<enum_type Selector> \
struct name { \
using type = typename util::switch_types<enum_type>::which<BOOST_PP_REPEAT(BOOST_PP_SEQ_SIZE(params),REFERENCE_FORMAT_ENUM,params)>::select<Selector>::template types<BOOST_PP_REPEAT(BOOST_PP_SEQ_SIZE(params),REFERENCE_FORMAT_CLASS,params)>::type; \
} \
JOINER_GEN_STRUCT(select,Test,TEST)
//select<hoge>::type -> int
//select<fuga>::type -> long
みたいな感じで書ける