我能想象的为类型转换器注册类型的最综合的方法是在
std::tuple
通过示例:如果要转换
std::int16_t
到
float
,
std::int32_t
double
和
std::int64_t
到
long double
,你可以
using
using list1 = std::tuple<std::int16_t, std::int32_t, std::int64_t>;
using list2 = std::tuple<float, double, long double>;
现在,给定以下结构和声明的函数
template <typename, typename, typename>
struct foo
{ using type = std::tuple<>; };
template <typename T1, typename T2>
struct foo<T1, T1, T2>
{ using type = std::tuple<T2>; };
template <typename T, typename ... Ts1, typename ... Ts2>
constexpr auto bar (std::tuple<Ts1...>, std::tuple<Ts2...>)
-> decltype( std::tuple_cat(
std::declval<typename foo<T, Ts1, Ts2>::type>()...) );
TypeConverter
成为
template <typename T>
using TypeConverter
= std::tuple_element_t<0u, decltype(bar<T>(std::declval<list1>(),
std::declval<list2>()))>;
但我想有两个不同的列表
std::tuple
s是合成的,但很难理解和维护。
因此,我提出了一种不太综合(但更易于理解和维护)的方法,它基于一对类型的单一列表
using list = std::tuple<std::pair<std::int16_t, float>,
std::pair<std::int32_t, double>,
std::pair<std::int64_t, long double>>;
现在
struct
并声明函数成为
template <typename, typename>
struct foo
{ using type = std::tuple<>; };
template <typename T1, typename T2>
struct foo<T1, std::pair<T1, T2>>
{ using type = std::tuple<T2>; };
template <typename T, typename ... Ts>
constexpr auto bar (std::tuple<Ts...>)
-> decltype( std::tuple_cat(
std::declval<typename foo<T, Ts>::type>()...) );
和
类型转换器
template <typename T>
using TypeConverter
= std::tuple_element_t<0u, decltype(bar<T>(std::declval<list>()))>;
下面是使用这两种解决方案编译C++17的完整示例(您可以启用第一个或第二个更改
#if 0
#include <tuple>
#include <type_traits>
#if 0
template <typename, typename, typename>
struct foo
{ using type = std::tuple<>; };
template <typename T1, typename T2>
struct foo<T1, T1, T2>
{ using type = std::tuple<T2>; };
template <typename T, typename ... Ts1, typename ... Ts2>
constexpr auto bar (std::tuple<Ts1...>, std::tuple<Ts2...>)
-> decltype( std::tuple_cat(
std::declval<typename foo<T, Ts1, Ts2>::type>()...) );
using list1 = std::tuple<std::int16_t, std::int32_t, std::int64_t>;
using list2 = std::tuple<float, double, long double>;
template <typename T>
using TypeConverter
= std::tuple_element_t<0u, decltype(bar<T>(std::declval<list1>(),
std::declval<list2>()))>;
#else
template <typename, typename>
struct foo
{ using type = std::tuple<>; };
template <typename T1, typename T2>
struct foo<T1, std::pair<T1, T2>>
{ using type = std::tuple<T2>; };
template <typename T, typename ... Ts>
constexpr auto bar (std::tuple<Ts...>)
-> decltype( std::tuple_cat(
std::declval<typename foo<T, Ts>::type>()...) );
using list = std::tuple<std::pair<std::int16_t, float>,
std::pair<std::int32_t, double>,
std::pair<std::int64_t, long double>>;
template <typename T>
using TypeConverter
= std::tuple_element_t<0u, decltype(bar<T>(std::declval<list>()))>;
#endif
int main ()
{
static_assert( std::is_same_v<float, TypeConverter<std::int16_t>> );
static_assert( std::is_same_v<double, TypeConverter<std::int32_t>> );
static_assert( std::is_same_v<long double, TypeConverter<std::int64_t>> );
}