mercredi 26 août 2015

Implementing lexicographic comparison for std::tuple in C++11

I'm trying to implement lexicographic comparison for std::tuple. I know the standard provides this. I'm doing it as a TMP exercise. I can't see why the code below doesn't work. Can anyone point me in the right direction?

I know the code below assumes operands of the same type. I am happy making this as a simplifying assumption.

I've looked at the VC++ 2013 and GCC 4.7 implementations. They both use non-standard helper classes to get the tail (i.e. all but the left-most element) from a tuple. I'd like to solve the problem with as little scaffolding as possible. Is it possible to do tuple comparison without something like get_tail?

#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;
}

Output: 0 1 0 1

Correct output would be: 1 1 1 1

Thanks in advance.

Aucun commentaire:

Enregistrer un commentaire