1

I have a class with a few simple members, and would like to implement a very simple < operator. This is what I started with:

inline bool operator< (const T& lhs, const T& rhs)  { return std::tie(lhs.GetA(), lhs.GetB()) < std::tie(rhs.GetA(), rhs.GetB()); }

Visual studio complains with

Warning 2   warning C4239: nonstandard extension used : 'argument' : conversion from 'A' to 'A &'

It seems the problem is that I am not using members, but rather functions, and am passing a rvalue to a non-const ref. I guess I could save GetA() in a local A, but would rather not.

How do I fix this?

I tried adding

A& GetARef() const { return a; }

which doesn't work as I am trying to return a non-const reference with const.

A& GetARef() { return a; }

This doesn't work, as lhs and rhs are const.

Now I am thinking maybe I should use std::tuple or maybe std::tie( std::cref(lhs.GetA()) ), or maybe a new template

template < typename... T >
std::tuple<const T&...> ctie( const T&... args )
{
    return std::tie( args... );
}

But I can't help but feel that I am over complicating this...

Cookie
  • 12,004
  • 13
  • 54
  • 83

1 Answers1

5

tie makes a tuple of lvalue references, and so doesn't work on temporaries (unless they are const, so that deduction of the tuple type gives const references).

You could use make_tuple to make a tuple of objects, or forward_as_tuple to get either lvalue or rvalue references depending on the arguments' value categories.

Alternatively, you could make your accessor work by returning a const reference to the const member:

A const & GetARef() const { return a; }
  ^^^^^
Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • Standard recommendation seems to be [std::tie](http://stackoverflow.com/questions/6218812/implementing-comparison-operators-via-tuple-and-tie-a-good-idea). Is `forward_as_tuple` always more appropriate then? – Cookie May 01 '14 at 14:27
  • 1
    @Cookie: It's common to use `tie` with the member variables themselves, to give a nice, concise implementation. If you insist on hiding them behind accessors, then either (a) make the operator a friend, or (b) change the accessors to return (const) references, giving the caller the choice of whether to copy them, or (c) use `forward_as_tuple` to deal with the gratuitously copied objects. – Mike Seymour May 01 '14 at 14:31
  • I think simply fixing the getter is the way to goo. – R. Martinho Fernandes May 01 '14 at 15:48
  • @R.MartinhoFernandes: I agree (with *goo*), returning a reference to an internal is cheap, however it means that `A` is no longer an implementation detail as it is exposed as part of the interface. A copy, while less efficient, can also become an object created from scratch, allowing more flexibility. – Matthieu M. May 01 '14 at 17:06