【问题标题】:Hana: How do I create a tuple of types from a variant?Hana:如何从变体创建类型元组?
【发布时间】:2015-11-12 18:56:08
【问题描述】:

如果我有一个变体,像这样:

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::tuple&lt;int, bool, std::string&gt;,还是hana::tuple&lt;hana::type&lt;int&gt;, hana::type&lt;bool&gt;, hana::type&lt;std::string&gt;&gt;。换句话说,你想要一个 types 的元组,还是一个包含 objects 的元组,其类型是变体的类型?
  • 类型元组。编辑了问题:)
  • 虽然也可以做一些通用的事情,ala meta::as_list 会很好(有吗?在文档中看不到)
  • 不,现在没有。然而,我一直在思考这个问题,但我从来没有真正找到一个令人满意的名字:github.com/boostorg/hana/issues/67。但是,我们将能够使用 boost::variant&lt;&gt;::types 是 MPL 序列这一事实。我正在写我的答案。
  • 如果您需要此功能用于任意模板,让我们在github.com/boostorg/hana/issues/67 上讨论它。我同意它会很有用,但我只需要一点说服力和一些帮助来命名这样的功能。

标签: c++ template-meta-programming boost-hana


【解决方案1】:

以下内容适用于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&lt;&gt;::typesmpl::list。这就是为什么我的回答需要一段时间才出现的原因;我正在执行那个:-)。

编辑

我没有解释为什么我使用constexpr auto my_tuple = ... 而不是using my_tuple = decltype(...)。好吧,原因很简单,因为知道my_tuple 的类型并不是很有用,因为你不能依赖它。实际上,如果您查看hana::type 的文档,就会发现您不能依赖hana::type&lt;T&gt; 是任何特定的东西。这有充分的理由,但从可用性的角度来看,这意味着您不能依赖 hana::tuple&lt;hana::type&lt;...&gt;, ...&gt; 的类型是任何特定的。在进行类型级计算时,更喜欢值级编码(因此auto my_tuple = ...)而不是类型级编码。这是 Hana 相对于 MPL 和朋友的特殊性,你应该尽量坚持下去,否则你会发现 Hana 真的很笨重(因为没有考虑到这一点)。

【讨论】:

  • 这太棒了,谢谢!尽管通用类型列表的解决方案认为将 hana 集成到任何现有代码库/库中非常有帮助
  • 我突然想到,应该小心使用基于专业化的通用解决方案。实际上,一些库组件使用可变参数模板的模拟,而 xxx&lt;int, bool, char&gt;xxx&lt;int, bool, char, mpl::void_, ...&gt;。我刚刚检查过,如果编译器支持,boost::variant 使用真正的可变参数模板,所以它现在可以工作了。但在一般情况下,我们仍然必须谨慎。
【解决方案2】:

这不使用任何 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...>;
};

现在,一个接受类型并返回 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 是因为提取任意模板的模板参数的类型函数似乎很有用。

【讨论】:

    【解决方案3】:

    前段时间我遇到过类似的转换。虽然无法找到这个想法的实际来源,或者它甚至可能是一种非常普遍的做法:

    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 tuple,我将展示一个 std::tuple 的示例

    convert<boost::variant<int, bool, string>, std::tuple>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-04
      • 1970-01-01
      • 2019-05-19
      • 1970-01-01
      • 2017-11-16
      • 1970-01-01
      相关资源
      最近更新 更多