我正在尝试实现对std::tuple的字典比较。我知道标准提供了这个。我在做TMP练习。我不明白为什么下面的代码不能工作。谁能给我指明正确的方向?
我知道下面的代码假设操作数具有相同的类型。我很高兴把这作为一个简化的假设。
我看过VC++ 2013年和GCC 4.7的实现。它们都使用非标准助手类从元组中获取尾(即除最左边元素外的所有元素)。我想用尽可能小的脚手架来解决这个问题。在没有类似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;
}产出:0 1 0 1
正确的输出是:1 1 1
提前谢谢。
发布于 2015-08-26 19:43:27
您的代码不能工作的原因是您的比较是反向的。你的第一个电话是:
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,因此您必须重写您的第一级调用:
return tuple_ops<decltype(x),0,sizeof...(T)>::less(x,y);现在终止的情况是:
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添加更多功能):
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>{})>{});
}对空箱进行重载:
template <typename X, typename Y>
bool is_less(X const&, Y const&, std::index_sequence<> ) {
return std::tuple_size<X>{} < std::tuple_size<Y>{};
}和递归情况的重载:
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...>{});
}
}发布于 2015-08-26 20:29:19
像个魅力一样工作。这是测试程序的一个版本,包含了Barry的提示。
#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;
}再次感谢。
https://stackoverflow.com/questions/32234978
复制相似问题