Using std::tie to implement operator< (by Anthony Williams at ACCU 2013)

I’ve used std::tie to unbind the underlying data from a std::tuple in the past:

auto t = std::make_tuple( 1, 42, 100 );
int a, b, c;
std::tie( a, b, c ) = t;

But I hadn’t seen this handy trick for using std::tie to implement operator<

#include <tuple>

struct S
{
  S(int a_, int b_, int c_) : a(a_), b(b_), c(c_)
  {}

  int a;
  int b;
  int c;
};

bool operator<( const S& lhs, const S& rhs )
{
  return std::tie( lhs.a, lhs.b, lhs.c )
       < std::tie( rhs.a, rhs.b, rhs.c );
}

int main()
{
  S s1( 1, 2, 3), s2 ( 1, 2, 4 ), s3 ( 0, 2, 3);

  std::cout << "s1 should be less than s2: " << (s1 < s2) << "\n"
            << "s3 should be less than s1: " << (s3 < s1) << "\n";

  return 0;
}

Notice that std::tie does not copy the variables (as per the earlier example, it takes them by reference). You can also mimic the use of use of underscore in F#

let f i = (i, i*2, i*4)
let a, _, c = f 5

using std::ignore

auto f = []( int i){ return std::tuple(i, i*2, i*4); }
int a, b;
std::tie( a, std::ignore, b ) = f( 5 );

5 Comments

Filed under C++ Code

5 responses to “Using std::tie to implement operator< (by Anthony Williams at ACCU 2013)

  1. I’ve used this idiom for a while, and, of course, it easily extends to all six of the relational operations, so you can write:

    struct S {
    {
    bool operator==( const S& that ) const
    { return tie(a,b,c) == tie(that.a,that.b,that.c); }
    bool operator<( const S& that ) const
    { return tie(a,b,c) decltype(tie(a,b,c) )
    { return tie(a,b,c); }
    public:
    bool operator==( const S& that ) const { return orderable() == that.orderable(); }
    // etc
    };

    At least here you only have *two* places you need to update when you add a member variable (and they’re right next to each other). Fortunately, there’s a proposal (that I was reading quite literally yesterday) to allow ‘auto’ to deduce the return type of member functions. so we get:

    struct S {
    protected:
    auto orderable() const { return tie(a,b,c); }
    public:
    bool operator==( const S& that ) const { return orderable() == that.orderable(); }
    // etc
    };

    Which is even simpler.

    • Thanks Andy – I like the orderable function. We have something similar in our F Sharp framework for implementing IComparable and related functions – I need to write the C++ equivalent soon, so I’ll give this a go.

  2. Hi Steve, I think wordpress ate my code there (there were actually *three*) forms. But the good news is that WG21 voted in “Return Type Deduction for normal functions” a few minutes ago, so the ‘orderable’ function becomes much easier to implement (or at least, maintain).

    (Of course, this still leaves the question of “is operator< the right name for an ordering operation" – and it's my belief that it's not)

  3. Pingback: C++17: structured bindings | musingstudio

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.