在编译时使用模板将枚举值映射到相应的类型?
Map enum values to corresponding types with templates at compile time?
我想在编译时使用模板将枚举值映射到相应的数据类型。我该怎么做?
例如
enum DataType {
UNSINGED_INT; // uint32_t
INT; // int32_t
UNSIGNED_CHAR; // uint8_t
CHAR; // int8_t
}
auto type = MapToDataType<DataType::UNSIGNED_CHAR>; // type will be uint8_t in this case
template <DataType> struct MapToDataTypeHelper {};
template <> struct MapToDataTypeHelper<INT> {using type = int;};
template <> struct MapToDataTypeHelper<UNSIGNED_INT> {using type = unsigned int;};
// ...
template <DataType X> using MapToDataType = typename MapToDataTypeHelper<X>::type;
MapToDataType<INT> x; // int x;
声明枚举 class。使用 class 避免名称空间污染。
#include <cstdint>
enum class DataType {
UNSIGNED_CHAR,
UNSIGNED_INT,
CHAR,
INT
};
为每个枚举条目指定一个模板:
template <DataType> struct MapToDataType_t;
template <> struct MapToDataType_t<DataType::UNSIGNED_CHAR> { using type = std::uint8_t; };
template <> struct MapToDataType_t<DataType::UNSIGNED_INT> { using type = std::unit32_t; };
template <> struct MapToDataType_t<DataType::CHAR> { using type = std::int8_t; };
template <> struct MapToDataType_t<DataType::INT> { using type = std::int32_t; };
每种类型的别名:
template <DataType T>
using MapToDataType = typename MapToDataType_t<T>::type;
如果您的 enum
包含可转换为 int
的值序列,没有空洞,并且从零开始(如您的示例所示),您可以使用 std::tuple
作为类型map 和 std::tuple_element
以提取所需的类型。
所以,写一个辅助结构体如下
template <DataType dt>
struct MapToDataType_helper
{
using type = typename std::tuple_element<
static_cast<std::size_t>(dt),
std::tuple<std::uint32_t,
std::int32_t,
std::uint8_t,
std::int8_t>
>::type;
};
您的地图是使用
的简单模板
template <DataType dt>
using MapToDataType = typename MapToDataType_helper<dt>::type;
例如,您可以验证
static_assert( std::is_same_v<MapToDataType<DataType::UNSIGNED_CHAR>,
std::uint8_t> );
携带编译时值和类型的一些标记类型和值:
template<auto x>
using constant_t = std::integral_constant<std::decay_t<decltype(x)>, x>;
template<auto x>
constexpr constant_t<x> constant{};
template<class T>
struct tag_t{using type=T;};
template<class T>
constexpr tag_t<T> tag{};
template<class X>
constexpr void type_map( X ) {}
template<auto X>
using get_type = typename decltype(type_map(constant<X>))::type;
好了,机器搞定了
现在只需添加这些:
inline auto type_map( constant_t<DataType::UNSIGNED_INT> ) { return tag<std::uint32_t>; }
inline auto type_map( constant_t<DataType::INT> ) { return tag<std::int32_t>; }
inline auto type_map( constant_t<DataType::UNSIGNED_CHAR> ) { return tag<std::uint8_t>; }
inline auto type_map( constant_t<DataType::CHAR> ) { return tag<std::int8_t>; }
而且有效。
支持其他枚举只是将 type_map
重载添加到相关 enum
的命名空间中。
一个宏
#define TYPE_MAP(FROM,...) \
inline auto type_map( constant_t<FROM> ) { return tag<__VA_ARGS__>; }
可以让它不那么冗长。
get_type
现在可以在任何具有相同机器设置的枚举上统一工作。
我想在编译时使用模板将枚举值映射到相应的数据类型。我该怎么做?
例如
enum DataType {
UNSINGED_INT; // uint32_t
INT; // int32_t
UNSIGNED_CHAR; // uint8_t
CHAR; // int8_t
}
auto type = MapToDataType<DataType::UNSIGNED_CHAR>; // type will be uint8_t in this case
template <DataType> struct MapToDataTypeHelper {};
template <> struct MapToDataTypeHelper<INT> {using type = int;};
template <> struct MapToDataTypeHelper<UNSIGNED_INT> {using type = unsigned int;};
// ...
template <DataType X> using MapToDataType = typename MapToDataTypeHelper<X>::type;
MapToDataType<INT> x; // int x;
声明枚举 class。使用 class 避免名称空间污染。
#include <cstdint>
enum class DataType {
UNSIGNED_CHAR,
UNSIGNED_INT,
CHAR,
INT
};
为每个枚举条目指定一个模板:
template <DataType> struct MapToDataType_t;
template <> struct MapToDataType_t<DataType::UNSIGNED_CHAR> { using type = std::uint8_t; };
template <> struct MapToDataType_t<DataType::UNSIGNED_INT> { using type = std::unit32_t; };
template <> struct MapToDataType_t<DataType::CHAR> { using type = std::int8_t; };
template <> struct MapToDataType_t<DataType::INT> { using type = std::int32_t; };
每种类型的别名:
template <DataType T>
using MapToDataType = typename MapToDataType_t<T>::type;
如果您的 enum
包含可转换为 int
的值序列,没有空洞,并且从零开始(如您的示例所示),您可以使用 std::tuple
作为类型map 和 std::tuple_element
以提取所需的类型。
所以,写一个辅助结构体如下
template <DataType dt>
struct MapToDataType_helper
{
using type = typename std::tuple_element<
static_cast<std::size_t>(dt),
std::tuple<std::uint32_t,
std::int32_t,
std::uint8_t,
std::int8_t>
>::type;
};
您的地图是使用
的简单模板template <DataType dt>
using MapToDataType = typename MapToDataType_helper<dt>::type;
例如,您可以验证
static_assert( std::is_same_v<MapToDataType<DataType::UNSIGNED_CHAR>,
std::uint8_t> );
携带编译时值和类型的一些标记类型和值:
template<auto x>
using constant_t = std::integral_constant<std::decay_t<decltype(x)>, x>;
template<auto x>
constexpr constant_t<x> constant{};
template<class T>
struct tag_t{using type=T;};
template<class T>
constexpr tag_t<T> tag{};
template<class X>
constexpr void type_map( X ) {}
template<auto X>
using get_type = typename decltype(type_map(constant<X>))::type;
好了,机器搞定了
现在只需添加这些:
inline auto type_map( constant_t<DataType::UNSIGNED_INT> ) { return tag<std::uint32_t>; }
inline auto type_map( constant_t<DataType::INT> ) { return tag<std::int32_t>; }
inline auto type_map( constant_t<DataType::UNSIGNED_CHAR> ) { return tag<std::uint8_t>; }
inline auto type_map( constant_t<DataType::CHAR> ) { return tag<std::int8_t>; }
而且有效。
支持其他枚举只是将 type_map
重载添加到相关 enum
的命名空间中。
一个宏
#define TYPE_MAP(FROM,...) \
inline auto type_map( constant_t<FROM> ) { return tag<__VA_ARGS__>; }
可以让它不那么冗长。
get_type
现在可以在任何具有相同机器设置的枚举上统一工作。