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::vectorboost::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 真的很笨拙(因为没有考虑到这一点)。