首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在C++11中实现std::tuple的词典对比

在C++11中实现std::tuple的词典对比
EN

Stack Overflow用户
提问于 2015-08-26 19:19:05
回答 2查看 636关注 0票数 1

我正在尝试实现对std::tuple的字典比较。我知道标准提供了这个。我在做TMP练习。我不明白为什么下面的代码不能工作。谁能给我指明正确的方向?

我知道下面的代码假设操作数具有相同的类型。我很高兴把这作为一个简化的假设。

我看过VC++ 2013年和GCC 4.7的实现。它们都使用非标准助手类从元组中获取尾(即除最左边元素外的所有元素)。我想用尽可能小的脚手架来解决这个问题。在没有类似get_tail的情况下可以进行元组比较吗?

代码语言:javascript
复制
#include <iostream>
#include <string>
#include <tuple>

// Pseudo-recursion.

template<class tupleT,std::size_t N>
struct tuple_ops {
    static bool less(const tupleT& x,const tupleT& y) {
        return std::get<N-1>(x) < std::get<N-1>(y) ||
            ( !(std::get<N-1>(y) < std::get<N-1>(x)) &&
              tuple_ops<tupleT,N-1>::less(x,y) );
    }
};

// Base Case.

template<class tupleT>
struct tuple_ops<tupleT,1> {
    static bool less(const tupleT& x,const tupleT& y) {
        return std::get<0>(x) < std::get<0>(y);
    }
};

// Convenience wrapper.

template<class... T>
bool operator<(const std::tuple<T...>& x,const std::tuple<T...>& y) {
    return tuple_ops<decltype(x),sizeof...(T)>::less(x,y);
}

int main() {
    using namespace std;

    auto tup0 = make_tuple(3.14,string("foo"),2.71);
    auto tup1 = make_tuple(4.01,string("foo"),2.01);
    auto tup2 = make_tuple(1,string("bar"),5);
    auto tup3 = make_tuple(1,string("foo"),5);

    cout <<  (::operator<(tup0,tup1))  << ' '
         <<  (::operator<(tup2,tup3))  << ' '
         << !(::operator<(tup1,tup0)) << ' '
         << !(::operator<(tup3,tup2)) << ' ';

    return 0;
}

产出:0 1 0 1

正确的输出是:1 1 1

提前谢谢。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-08-26 19:43:27

您的代码不能工作的原因是您的比较是反向的。你的第一个电话是:

代码语言:javascript
复制
return tuple_ops<decltype(x),sizeof...(T)>::less(x,y);

它将调用tuple_ops<Type, 3>::less(),其第一个操作将比较std::get<2>(x)std::get<2>(y)。所以你先比较最后一个元素。

您必须从0开始,然后进入N,因此您必须重写您的第一级调用:

代码语言:javascript
复制
return tuple_ops<decltype(x),0,sizeof...(T)>::less(x,y);

现在终止的情况是:

代码语言:javascript
复制
template <typename Tuple, size_t N>
struct tuple_ops<Tuple, N, N> {
    static bool less(const Tuple&, const Tuple&) { return false; }
};

避免专门化的一个更简单的方法是使用索引序列(并借用Yakk的now-deleted answer添加更多功能):

代码语言:javascript
复制
template <class X, class Y>
bool operator<(const X& x, const Y& y) {
    return is_less(x, y,
        std::make_index_sequence<std::min(std::tuple_size<X>{},
                                          std::tuple_size<Y>{})>{});
}

对空箱进行重载:

代码语言:javascript
复制
template <typename X, typename Y>
bool is_less(X const&, Y const&, std::index_sequence<> ) {
    return std::tuple_size<X>{} < std::tuple_size<Y>{};
}

和递归情况的重载:

代码语言:javascript
复制
template <typename X, typenmae Y, size_t I, size_t... Is>
bool is_less(X const& x, Y const& y, std::index_sequence<I, Is...> ) {
    if (std::get<I>(x) < std::get<I>(y)) {
        return true;
    }
    else if (std::get<I>(y) < std::get<I>(x)) {
        return false;
    }
    else {
        return is_less(x, y, std::index_sequence<Is...>{});
    }
}
票数 0
EN

Stack Overflow用户

发布于 2015-08-26 20:29:19

像个魅力一样工作。这是测试程序的一个版本,包含了Barry的提示。

代码语言:javascript
复制
#include <iostream>
#include <string>
#include <tuple>

// Pseudo-recursion.

template<class tupleT,std::size_t J,std::size_t N>
struct tuple_ops {
    static bool less(const tupleT& x,const tupleT& y) {
        return std::get<J>(x) < std::get<J>(y) ||
            ( !(std::get<J>(y) < std::get<J>(x)) &&
                tuple_ops<tupleT,J+1,N>::less(x,y) );
    }
};

// Base Case.

template <typename Tuple, size_t N>
struct tuple_ops<Tuple,N,N> {
    static bool less(const Tuple&, const Tuple&) {return false;}
};

// Convenience wrapper.

template<class... T>
bool operator<(const std::tuple<T...>& x,const std::tuple<T...>& y) {
    return tuple_ops<decltype(x),0,sizeof...(T)>::less(x,y);
}

int main() {
    using namespace std;

    auto tup0 = make_tuple(3.14,string("foo"),2.71);
    auto tup1 = make_tuple(4.01,string("foo"),2.01);
    auto tup2 = make_tuple(1,string("bar"),5);
    auto tup3 = make_tuple(1,string("foo"),5);

    cout <<  (::operator<(tup0,tup1)) << ' '
         <<  (::operator<(tup2,tup3)) << ' '
         << !(::operator<(tup1,tup0)) << ' '
         << !(::operator<(tup3,tup2)) << ' ';

    return 0;
}

再次感谢。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32234978

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档