类型列表上的编译时映射
Compile-time map on a type list
我正在寻找一种惯用的方法来为类型列表中的每个元素应用类型级转换。到目前为止,我想出了以下方法,它按预期工作:
namespace impl_
{
template <template <typename> typename, typename>
struct MapVariant;
template <template <typename> typename F, typename... Ts>
struct MapVariant<F, std::variant<Ts...>>
{
using Result = std::variant<F<Ts>...>;
};
}
template <typename Variant, template <typename> typename Transform>
using MapVariant = typename impl_::MapVariant<Transform, Variant>::Result;
测试:
using TestVariant = std::variant<int, char, std::array<float, 0>>;
template <typename Arg>
using TypeTransform = std::array<Arg, 0>;
static_assert(
std::is_same_v<MapVariant<TestVariant, TypeTransform>, //
std::variant<std::array<int, 0>, std::array<char, 0>, std::array<std::array<float, 0>, 0>> //
>);
现在我想概括 MapVariant
以接受用类型列表参数化的任意容器,而不仅仅是 std::variant
(例如,std::tuple
)。我天真的解决方案不起作用:
template <template <typename...> class C, template <typename> typename F, typename... Ts>
using MapVariant = C<F<Ts>...>;
这里有一个更加冗长的方法,更接近原始方法,但也是功能失调的:
namespace impl_
{
template <template <typename> typename, typename, template <typename...> class, typename>
struct MapVariant;
template <template <typename> typename F, typename Unused, template <typename...> class C, typename... Ts>
struct MapVariant<F, Unused, C, C<Ts...>>
{
using Result = C<F<Ts>...>;
};
}
template <template <typename...> class Variant, template <typename> typename Transform, typename... Ts>
using MapVariant = typename impl_::MapVariant<Transform, Variant<Ts...>, Variant, Ts...>::Result;
Clang 说“模板模板参数的模板参数必须是 class 模板或类型别名模板”。我知道编译器无法解压缩 TestVariant
,因为显然某些类型信息在通过 using
定义时丢失了,但我不知道如何解决这个问题。
完全可以做到这一点吗?
感谢 Fureeish 我设法通过一个小改动解决了这个问题:
template <template <typename> typename, typename>
struct MapVariant;
template <template <typename...> class C, template <typename> typename F, typename... Ts>
struct MapVariant<F, C<Ts...>>
{
using Result = C<F<Ts>...>;
};
不需要更改外部别名。关键区别在于模板参数的顺序不正确——如果我多加注意的话我会注意到的。嗯。再次感谢,Fureeish。
我会用函数而不是模板来做到这一点。清洁工
template<class T>struct tag_t{using type=T;};
template<class T>constexpr tag_t<T> tag{};
template<template<class...>class Z>
struct ztag_t{
template<class...Ts>using result=Z<Ts...>;
template<class...Ts>
constexpr auto operator()(tag_t<Ts>...)const{ return tag<result<Ts...>>; }
};
template<template<class...>class Z>
constexpr ztag_t<Z> ztag{};
template<class Tag>
using type_t=typename Tag::type;
#define TYPE_T(...) type_t<decltype(__VA_ARGS__)>
template <template<class...>class Z,class...Ts>
constexpr auto fmap(auto f, tag_t<Z<Ts...>>){
return f(tag<Ts>...);
};
使用:
using bob=std::tuple<int,double,char>;
using as_var=TYPE_T(fmap(ztag<std::variant>, tag<bob>));
是不是很漂亮。
可能有错别字。
我正在寻找一种惯用的方法来为类型列表中的每个元素应用类型级转换。到目前为止,我想出了以下方法,它按预期工作:
namespace impl_
{
template <template <typename> typename, typename>
struct MapVariant;
template <template <typename> typename F, typename... Ts>
struct MapVariant<F, std::variant<Ts...>>
{
using Result = std::variant<F<Ts>...>;
};
}
template <typename Variant, template <typename> typename Transform>
using MapVariant = typename impl_::MapVariant<Transform, Variant>::Result;
测试:
using TestVariant = std::variant<int, char, std::array<float, 0>>;
template <typename Arg>
using TypeTransform = std::array<Arg, 0>;
static_assert(
std::is_same_v<MapVariant<TestVariant, TypeTransform>, //
std::variant<std::array<int, 0>, std::array<char, 0>, std::array<std::array<float, 0>, 0>> //
>);
现在我想概括 MapVariant
以接受用类型列表参数化的任意容器,而不仅仅是 std::variant
(例如,std::tuple
)。我天真的解决方案不起作用:
template <template <typename...> class C, template <typename> typename F, typename... Ts>
using MapVariant = C<F<Ts>...>;
这里有一个更加冗长的方法,更接近原始方法,但也是功能失调的:
namespace impl_
{
template <template <typename> typename, typename, template <typename...> class, typename>
struct MapVariant;
template <template <typename> typename F, typename Unused, template <typename...> class C, typename... Ts>
struct MapVariant<F, Unused, C, C<Ts...>>
{
using Result = C<F<Ts>...>;
};
}
template <template <typename...> class Variant, template <typename> typename Transform, typename... Ts>
using MapVariant = typename impl_::MapVariant<Transform, Variant<Ts...>, Variant, Ts...>::Result;
Clang 说“模板模板参数的模板参数必须是 class 模板或类型别名模板”。我知道编译器无法解压缩 TestVariant
,因为显然某些类型信息在通过 using
定义时丢失了,但我不知道如何解决这个问题。
完全可以做到这一点吗?
感谢 Fureeish 我设法通过一个小改动解决了这个问题:
template <template <typename> typename, typename>
struct MapVariant;
template <template <typename...> class C, template <typename> typename F, typename... Ts>
struct MapVariant<F, C<Ts...>>
{
using Result = C<F<Ts>...>;
};
不需要更改外部别名。关键区别在于模板参数的顺序不正确——如果我多加注意的话我会注意到的。嗯。再次感谢,Fureeish。
我会用函数而不是模板来做到这一点。清洁工
template<class T>struct tag_t{using type=T;};
template<class T>constexpr tag_t<T> tag{};
template<template<class...>class Z>
struct ztag_t{
template<class...Ts>using result=Z<Ts...>;
template<class...Ts>
constexpr auto operator()(tag_t<Ts>...)const{ return tag<result<Ts...>>; }
};
template<template<class...>class Z>
constexpr ztag_t<Z> ztag{};
template<class Tag>
using type_t=typename Tag::type;
#define TYPE_T(...) type_t<decltype(__VA_ARGS__)>
template <template<class...>class Z,class...Ts>
constexpr auto fmap(auto f, tag_t<Z<Ts...>>){
return f(tag<Ts>...);
};
使用:
using bob=std::tuple<int,double,char>;
using as_var=TYPE_T(fmap(ztag<std::variant>, tag<bob>));
是不是很漂亮。
可能有错别字。