В любом случае будет сразу один переключатель, если вы не будете использовать полиморфизм во время выполнения. Если вы будете использовать статический полиморфизм, вам понадобится либо специализация, либо переключатель.
Хороший подход к использованию отображения type2enum и enum2type:
type2enum:
// preparition
template<class T> type2enum();
#define TYPE2ENUM_SPEC(TYPE, ENUM) \
template<> type2enum<TYPE>() \
{ return ENUM; }
enum { T1enum, T2enum, T3enum }
TYPE2ENUM_SPEC(type1_t, T1enum);
TYPE2ENUM_SPEC(type2_t, T2enum);
TYPE2ENUM_SPEC(some_third_type_t, T3enum);
и обратный enum2type:
// preparition
template<int Enum>
struct enum2type;
#define ENUM2TYPE_SPEC(ENUM, TYPE) \
template<> struct Enum2Type<ENUM> \
{ typedef TYPE type_t; }
// and generic macro
#define CREATE_TYPE_MAPPING(TYPE, INTEGER) \
#define TYPE2ENUM_SPEC(TYPE, INTEGER) \
#define ENUM2TYPE_SPEC(INTEGER, TYPE)
и образец кода:
у нас есть Type1, Type2, Type3 и enum:
enum {T1, T2, T3};
CREATE_TYPE_MAPPING(Type1, T1);
CREATE_TYPE_MAPPING(Type2, T2);
CREATE_TYPE_MAPPING(Type3, T3);
, чем использовать его для отображения типа enum:
int typeId = type2enum<Type1>();
или постоянное перечисление для типа:
typedef Enum2Type<ConstEnumType>::type_t some_t;
и для выполнения enum во время выполнения вы используете что-то вроде:
template<class ObjT>
void DoWithTypeIdValue(int enumValue, const ObjT& obj)
{
switch(enumValue)
{
case enumType1:
obj.do<Enum2Type<enumType1>::type_t>();
break;
case enumType2:
obj.do<Enum2Type<enumType2>::type_t>();
break;
case enumType3:
obj.do<Enum2Type<enumType3>::type_t>();
break;
default:
assert(!"Unknown type constant");
}
}