【问题标题】:uniform way to remove duplicates from a typelist using boost hana使用 boost hana 从类型列表中删除重复项的统一方法
【发布时间】:2016-12-04 01:05:24
【问题描述】:

我正在尝试熟悉 boost::hana。作为练习,我想创建一个函数,该函数将使用用户提供的比较函数从 hana::tuple 中删除重复项。我面临的问题与使用hana::type_c 将类型存储为对象有关。这是我所拥有的

#include <boost/hana/equal.hpp>
#include <boost/hana/tuple.hpp>
#include <boost/hana/unpack.hpp>
#include <boost/hana/pair.hpp>
#include <boost/hana/any_of.hpp>
#include <boost/hana/second.hpp>
#include <boost/hana/fold.hpp>
#include <boost/hana/core/make.hpp>
#include <boost/hana/core/tag_of.hpp>

#include <iostream>

template <class>
struct what_is;

namespace hana = boost::hana;

// simply push back an element to the sequence
auto push_back = [](auto seq, auto t) {

    using namespace boost::hana;
    return unpack(seq, [&](auto&&... element){return make<typename tag_of<decltype(seq)>::type>(element..., t);});
};

// this is the main function
auto remove_duplicates = [](auto seq, auto comp) {

    using namespace boost::hana;

    auto f = [&](auto state, auto el){
        return if_( any_of(state, partial(comp, el)),
                   [=](){return state;},
                   [=](){return push_back(state, el);})();
    };

    return fold(seq, make<typename tag_of<decltype(seq)>::type>(), f);
};

// user-defined comparison function
// elements are considered equal if only second element of pairs are equal
auto comp_pair = [](auto&& t1, auto&& t2) {

    using namespace boost::hana;
    return equal(second(t1), second(t2));
};


int main() {

    auto my_tuple1 = hana::tuple_t<int, float, double, int, float>;
    auto no_dups1 = remove_duplicates(my_tuple1, hana::equal); // this is fine, decltype(no_dups1) -> tuple< type<int>, type<float>, type<double> >

    auto my_tuple2 = hana::tuple_t< hana::pair<int, int>, hana::pair<float, int>, hana::pair<float, float> >;
//    auto no_dups2 = remove_duplicates(my_tuple2, comp_pair); // what I want here is tuple< type<pair<int, int>>, type<pair<float, float>> >
}

最后一行产生了问题,因为没有第二个元素可以从 hana::type&lt;pair&lt;X,Y&gt;&gt; 中提取。为此,我必须创建一个非常丑陋的序列,例如tuple&lt; pair&lt;type&lt;int&gt;, type&lt;int&gt;&gt;, pair&lt;type&lt;double&gt;, type&lt;int&gt;&gt;, pair&lt;type&lt;float&gt;, type&lt;double&gt;&gt; &gt;。正如您可以想象的那样,这可能会很快变得很糟糕,例如,如果我有一个序列tuple&lt;int, pair&lt;X,Y&gt;, double, float&gt; 等。有什么办法可以创建一个统一的方法来处理这个问题?我来自 MPL/fusion 背景,在那里我可以直接使用类型而无需包装类型。谢谢

【问题讨论】:

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


    【解决方案1】:

    与 Fusion 不同,Hana 不会将值隐式转换为类型。一般来说,这很好,因为这意味着您可以使用更具表现力的值语法。另一方面,对于某些您真正想要提取包装类型的用例,您必须使用 Hana 显式执行此操作,而 Fusion 在后台为您完成此操作。

    对于您想要实现的目标,我看到了两种选择。第一个解决方案是更改您的 comp_pair 函数,以便它自己解开对:

    template <typename T1, typename U1, typename T2, typename U2>
    constexpr auto comp_pair(hana::basic_type<hana::pair<T1, U1>>,
                             hana::basic_type<hana::pair<T2, U2>>)
    {
        return hana::type_c<U1> == hana::type_c<U2>;
    }
    
    ...
    
    auto no_dups2 = remove_duplicates(my_tuple2, [](auto pair1, auto pair2) {
        return comp_pair(pair1, pair2);
    });
    

    第二个解决方案,我觉得更惯用,实际上是把你的类型保存为对象:

    // This could arguably be part of Hana, just like we provide tuple_t
    template <typename T, typename U>
    constexpr auto pair_t = hana::make_pair(hana::type_c<T>, hana::type_c<U>);
    
    auto tuple2 = hana::make_tuple(pair_t<int, int>, pair_t<double, int>, pair_t<float, double>);
    auto nodups2 = remove_duplicates(tuple2, [](auto p1, auto p2) {
      return hana::second(p1) == hana::second(p2);
    });
    

    但是,你说:

    您可以想象这会很快变得很糟糕,例如,如果我有一个序列 tuple&lt;int, pair&lt;X,Y&gt;, double, float&gt; 等。有什么方法可以创建一个统一的方法来处理这个问题?

    我不确定我是否关注这里。您是说您可能想要tuple&lt;type&lt;int&gt;, pair&lt;type&lt;X&gt;, type&lt;Y&gt;&gt;, type&lt;double&gt;, type&lt;float&gt;&gt; 之类的东西,并且正在寻找实现此目标的通用方法吗?如果是这样,那么我必须说我高度怀疑有更好的方法来实现你想要做的任何事情。如果您提供更多背景信息,我可以尝试提供帮助。

    希望这会有所帮助!

    【讨论】:

    • 谢谢你,做到了。统一,我的意思是我希望我的remove_duplicates 函数假设元组中的所有元素都用type&lt;X&gt; 包装。现在,这适用于my_tuple1,但不适用于my_tuple2,它必须以完全不同的方式包装为 'tuple, type>...>`(注意那里没有 type 包装 pairs)。我认为以您所做的方式创建 comp_pair 函数让我大致了解了如何通用地执行此操作。顺便谢谢你的图书馆!很棒的东西
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-04
    • 2015-08-02
    相关资源
    最近更新 更多