Hana:如何从变体创建类型元组?
Hana: How do I create a tuple of types from a variant?
如果我有一个变体,像这样:
using my_variant = boost::variant<int, bool, std::string>;
是否有一种简单的方法可以将变体可以包含的类型提取到 Boost.Hana 元组中,以便满足以下条件:
using boost::hana::type;
static_assert(std::is_same<my_tuple, boost::hana::tuple<type<int>, type<bool>, type<std::string>>>{});
这没有使用任何 hana 功能,但应该可以。
首先,一个 transcribe
类型函数,它接受一个模板和一个不同模板的实例,并将第二个中的类型转录到第一个中:
template<template<class...>class To, class From>
struct transcribe;
template<template<class...>class To, class From>
using transcribe_t=typename transcribe<To,From>::type;
template<template<class...>class Z, template<class...>class Src, class...Ts>
struct transcribe<Z, Src<Ts...>> {
using type=Z<Ts...>;
};
现在,一个接受类型的模板,以及 returns hana 类型的 hana 元组:
template<class...Ts>
using tuple_of_types = boost::hana::tuple<boost::hana::type<Ts>...>;
我们完成了:
template<class Src>
using get_types_from = transcribe_t< tuple_of_types, Src >;
using result = get_types_from< my_variant >;
get_types_from
是因为提取任意模板的模板参数的类型函数似乎很有用。
前段时间我遇到过类似的转换。虽然无法找到这个想法的实际来源,或者它甚至可能是一种非常普遍的做法:
template<class From, template<class...> class To> struct convert_impl;
template<template<class...> class From, class... Types,
template<class...> class To>
struct convert_impl<From<Types...>, To>
{
using converted_type = To<Types...>;
};
template<class From, template<class...> class To>
using convert = typename convert_impl<From, To>::converted_type;
因为我不确定 boost hana 元组,我将用 std::tuple
来展示一个例子
convert<boost::variant<int, bool, string>, std::tuple>
以下将适用于 develop
(自 e13d826 起):
#include <boost/hana.hpp>
#include <boost/hana/ext/boost/mpl.hpp>
#include <boost/variant.hpp>
#include <string>
namespace hana = boost::hana;
using my_variant = boost::variant<int, bool, std::string>;
constexpr auto my_tuple = hana::to<hana::tuple_tag>(my_variant::types{});
// Note:
// In general, don't use std::is_same to compare hana::tuple; use == in
// because it will also work if the tuple contains hana::basic_types.
static_assert(my_tuple == hana::tuple_t<int, bool, std::string>, "");
e13d826 所做的是添加对 mpl::list
的支持;之前只支持mpl::vector
,boost::variant<>::types
是一个mpl::list
。这就是为什么我的回答花了一段时间才出来;我正在实施 :-).
编辑
我没有解释为什么我使用 constexpr auto my_tuple = ...
而不是 using my_tuple = decltype(...)
。嗯,原因很简单,因为知道 my_tuple
的类型并不是很有用,因为你不能依赖它。实际上,如果您查看 hana::type
的文档,就会发现您不能依赖 hana::type<T>
是任何特定的东西。这有充分的理由,但从可用性的角度来看,这意味着您不能依赖 hana::tuple<hana::type<...>, ...>
的类型是任何特定的。在进行类型级计算时,更喜欢值级编码(因此 auto my_tuple = ...
)而不是类型级编码。这是 Hana 相对于 MPL 和朋友们的特殊性,你应该尽可能地坚持下去,否则你会发现 Hana 真的很笨拙(因为没有考虑到这一点)。
如果我有一个变体,像这样:
using my_variant = boost::variant<int, bool, std::string>;
是否有一种简单的方法可以将变体可以包含的类型提取到 Boost.Hana 元组中,以便满足以下条件:
using boost::hana::type;
static_assert(std::is_same<my_tuple, boost::hana::tuple<type<int>, type<bool>, type<std::string>>>{});
这没有使用任何 hana 功能,但应该可以。
首先,一个 transcribe
类型函数,它接受一个模板和一个不同模板的实例,并将第二个中的类型转录到第一个中:
template<template<class...>class To, class From>
struct transcribe;
template<template<class...>class To, class From>
using transcribe_t=typename transcribe<To,From>::type;
template<template<class...>class Z, template<class...>class Src, class...Ts>
struct transcribe<Z, Src<Ts...>> {
using type=Z<Ts...>;
};
现在,一个接受类型的模板,以及 returns hana 类型的 hana 元组:
template<class...Ts>
using tuple_of_types = boost::hana::tuple<boost::hana::type<Ts>...>;
我们完成了:
template<class Src>
using get_types_from = transcribe_t< tuple_of_types, Src >;
using result = get_types_from< my_variant >;
get_types_from
是因为提取任意模板的模板参数的类型函数似乎很有用。
前段时间我遇到过类似的转换。虽然无法找到这个想法的实际来源,或者它甚至可能是一种非常普遍的做法:
template<class From, template<class...> class To> struct convert_impl;
template<template<class...> class From, class... Types,
template<class...> class To>
struct convert_impl<From<Types...>, To>
{
using converted_type = To<Types...>;
};
template<class From, template<class...> class To>
using convert = typename convert_impl<From, To>::converted_type;
因为我不确定 boost hana 元组,我将用 std::tuple
来展示一个例子convert<boost::variant<int, bool, string>, std::tuple>
以下将适用于 develop
(自 e13d826 起):
#include <boost/hana.hpp>
#include <boost/hana/ext/boost/mpl.hpp>
#include <boost/variant.hpp>
#include <string>
namespace hana = boost::hana;
using my_variant = boost::variant<int, bool, std::string>;
constexpr auto my_tuple = hana::to<hana::tuple_tag>(my_variant::types{});
// Note:
// In general, don't use std::is_same to compare hana::tuple; use == in
// because it will also work if the tuple contains hana::basic_types.
static_assert(my_tuple == hana::tuple_t<int, bool, std::string>, "");
e13d826 所做的是添加对 mpl::list
的支持;之前只支持mpl::vector
,boost::variant<>::types
是一个mpl::list
。这就是为什么我的回答花了一段时间才出来;我正在实施 :-).
编辑
我没有解释为什么我使用 constexpr auto my_tuple = ...
而不是 using my_tuple = decltype(...)
。嗯,原因很简单,因为知道 my_tuple
的类型并不是很有用,因为你不能依赖它。实际上,如果您查看 hana::type
的文档,就会发现您不能依赖 hana::type<T>
是任何特定的东西。这有充分的理由,但从可用性的角度来看,这意味着您不能依赖 hana::tuple<hana::type<...>, ...>
的类型是任何特定的。在进行类型级计算时,更喜欢值级编码(因此 auto my_tuple = ...
)而不是类型级编码。这是 Hana 相对于 MPL 和朋友们的特殊性,你应该尽可能地坚持下去,否则你会发现 Hana 真的很笨拙(因为没有考虑到这一点)。