2016-12-04 72 views
0

我想熟悉boost :: hana。作为一个练习,我想创建一个函数,使用用户提供的比较函数从hana :: tuple中移除重复项。我面临的问题与使用hana::type_c将类型存储为对象有关。以下是我有统一的方式来删除使用助推hana的类型列表重复

#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<pair<X,Y>>提取没有第二个元素。为了这个工作,我将不得不创建一个非常难看的序列,如tuple< pair<type<int>, type<int>>, pair<type<double>, type<int>>, pair<type<float>, type<double>> >。正如你可以想象的那样,这可能会很快变坏,例如,如果我有一个序列tuple<int, pair<X,Y>, double, float>等等。有什么办法可以创建一个统一的方式来处理这个问题吗?我来自MPL /融合背景,我可以直接使用这些类型而不需要包装类型。谢谢

回答

2

与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<int, pair<X,Y>, double, float>等。这能够生长不好的真的很快,比如有什么办法,我可以创造一个统一的方式去有这个?

我不确定我在这里。你是说你可能想要像tuple<type<int>, pair<type<X>, type<Y>>, type<double>, type<float>>这样的东西,并且正在寻找一种达到此目的的通用方式?如果是这样,那么我必须说,我高度怀疑有一个更好的方法来实现你想要做的任何事情。如果您提供更多上下文,我可以尝试提供帮助。

希望这会有所帮助!

+0

谢谢,这是做到了。通过统一,我的意思是我希望我的'remove_duplicates'函数假定元组中的所有元素都被''类型包装。现在,这对'my_tuple1'很好,但对'my_tuple2'没有用,它必须以与'元组,类型> ...>一样的完全不同的方式进行包装''(注意,没有'type'包装' pair's)。我认为按照你的方式创建'comp_pair'函数给了我一般的想法,即如何做到这一点。顺便谢谢你的图书馆!真棒的东西 – linuxfever