我需要在C ++中实现类型转换器,以将某种类型转换为另一种类型。例如,将int16_t
转换为float
,将int64_t
转换为double
。我已经使用模板专门化实现了一个:
template<class T>
struct TypeConverter
{
};
template<>
struct TypeConverter<int16_t>
{
using type = float;
};
template<>
struct TypeConverter<int64_t>
{
using type = double;
};
TEST(Exp, TypeConveter) {
static_assert(std::is_same_v<TypeConverter<int16_t>::type, float>);
static_assert(std::is_same_v<TypeConverter<int64_t>::type, double>);
}
使用C ++ 17 tmp功能是否有更好的方法(更紧凑)?
答案 0 :(得分:3)
另一种简单方式(与C ++ 11兼容):
template<class T> struct Type {};
float type_convert(Type<int16_t>);
double type_convert(Type<int64_t>);
int main() {
static_assert(std::is_same_v<decltype(type_convert(Type<int16_t>{})), float>);
static_assert(std::is_same_v<decltype(type_convert(Type<int64_t>{})), double>);
}
此方法的优点在于,它使用基于参数的名称查找(ADL)查找相应的type_convert
函数 declaration (无需 definition ) 。如果您需要处理用户定义的类型(UDT),则可以在声明它们的相同名称空间中为它们添加type_convert
的相应重载(而不必打开traits命名空间来定义特征的另一个特殊化)您的UDT的课程模板)。例如:
namespace N {
struct MyType;
long double type_convert(Type<MyType>);
}
然后:
// type_convert is found by ADL.
static_assert(std::is_same_v<decltype(type_convert(Type<N::MyType>{})), long double>);
答案 1 :(得分:1)
CE C ++ 17:https://gcc.godbolt.org/z/iY8Qoa
CE C ++ 11:https://gcc.godbolt.org/z/ApuxZj
用户代码
#include<TypeMap.h>
#include<cstdlib>
using TMap = TypeMap <
std::pair<int16_t, float>,
std::pair<int64_t, double>
>;
void foo() {
static_assert(std::is_same_v<TMap::get<int16_t>, float>);
static_assert(std::is_same_v<TMap::get<int64_t>, double>);
static_assert(std::is_same_v<TMap::get<int>, NotFound>);
}
TypeMap.h
#include<type_traits>
#include<utility>
struct NotFound;
template<class... TPs>
struct TypeMap {
template<class T>
using get = NotFound;
};
template<class TP1, class... TPs>
struct TypeMap<TP1, TPs...> {
template<class T>
using get = std::conditional_t< std::is_same_v<T, typename TP1::first_type>
, typename TP1::second_type
, typename TypeMap<TPs...>::template get<T> >;
};
答案 2 :(得分:0)
我可以想像的为类型转换器注册类型的最综合的方法是在std::tuple
(或类似的东西)中列出几个类型的列表。
例如:如果要将std::int16_t
转换为float
,将std::int32_t
转换为double
,将std::int64_t
转换为long double
,则可以{ {1}}定义几种类型
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
现在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>()...) );
TypeConverter
以下是具有两种解决方案的完整的C ++ 17示例(您可以启用第一个或第二个更改template <typename T>
using TypeConverter
= std::tuple_element_t<0u, decltype(bar<T>(std::declval<list>()))>;
)
#if 0