3

I would like to write a comparator which compares tuples of different length but have the same "prefix". Consider following case, I have two tuples.

auto t1 = std::make_tuple(10, "Test1");
auto t2 = std::make_tuple(10, "Test", 3.14);


I would like to apply "less" for t1 < t2, where only two first members of tuple are compared (same type?) and the third one is just omited. Is it possible?

kreuzerkrieg
  • 3,009
  • 3
  • 28
  • 59

2 Answers2

7

Well, since no one has chimed in, here is the solution. It uses C++14 std::index_sequence, so the recursion is hidden in it.

#include <tuple>
#include <utility>

template<class... ARGS1, class... ARGS2, std::size_t... Is>
bool tuple_compare_helper(const std::tuple<ARGS1...>& lhs, const std::tuple<ARGS2...>& rhs, std::index_sequence<Is...> ) {
  return std::tie(std::get<Is>(lhs)...) < std::tie(std::get<Is>(rhs)...);

}

template<class... ARGS1, class... ARGS2> 
bool tuple_compare(const std::tuple<ARGS1...>& lhs, const std::tuple<ARGS2...>& rhs) {
  const auto min_size = std::min(sizeof...(ARGS1), sizeof...(ARGS2));

  return tuple_compare_helper(lhs, rhs, std::make_index_sequence<min_size>());
}

// test driver
#include <iostream>
int main() {
  auto t1 = std::make_tuple(1, std::string("One"), 2.0);
  auto t2 = std::make_tuple(3, std::string("Two"));


  std::cout << tuple_compare(t2, t1) << "\n";
}
SergeyA
  • 61,605
  • 5
  • 78
  • 137
  • 1
    `std::make_tuple` will... make a new tuple of copies just to compare corresponding elements, which is not the most efficient approach. consider using `std::tie` for that – Piotr Skotnicki Feb 22 '16 at 21:09
  • @PiotrSkotnicki, just what I was thinking :) Will edit and replace. – SergeyA Feb 22 '16 at 21:11
  • Ok, quite interesting technique, however, I dont understand what code is going to be generated when std::get(lhs)... is called? Could you elaborate please? In any case this is the correct answer – kreuzerkrieg Feb 23 '16 at 05:29
  • 1
    `std::min` is `constexpr` nowadays so your expression for `min_size` can be simplified a bit. – MSalters Feb 23 '16 at 09:55
  • @MSalters, fair enough, didn't know this. Will edit. – SergeyA Feb 23 '16 at 14:17
  • 1
    @kreuzerkrieg, this is called *pack expansion*: http://en.cppreference.com/w/cpp/language/parameter_pack#Pack_expansion . Basically, it will be replaced with `(std::get<0>(lhs), std::get<1>(lhs>, ..., std::get(lhs))`, where N is the last index in Is. – SergeyA Feb 23 '16 at 14:21
  • However, if you do not like pack expansion, you can achieve the same functionality by recursively calling `<` on every member of the tuple. – SergeyA Feb 23 '16 at 14:42
  • Ah, I guess I've overlooked the pack expansion in function call, thanks! And sure I like it, compact and elegant, thanks again! – kreuzerkrieg Feb 23 '16 at 16:33
-6

t1 and t2 are of purely different types,so you can't compare them. (tuples are template type; they aren't polymorphic at runtime) I think the only t-way to do this is a temporary tuple which takes t2 first and seconds elements to do the comparison

bisthebis
  • 523
  • 2
  • 10