Tomilov Anatoliy
Tomilov Anatoliy

Reputation: 16741

Can an operator to recognize rvalue?

I have some STL container type T, say template< typename F > using T = std::vector< F >;. I want to be able to write the following code:

typedef std::string F;
T< F > v(2, "a"), w(3, "b");
v += std::move(w);
std::cout << "v : ";
std::copy(std::begin(v), std::end(v), std::ostream_iterator< F >(std::cout, "|"));
std::cout << std::endl << "w : ";
std::copy(std::begin(w), std::end(w), std::ostream_iterator< F >(std::cout, "|"));
std::cout << std::endl;

and get the output:

v : a|a|b|b|b|
w : |||

I.e. I want to be able to append all the contents of the source w to the end of the destination v by means of "std::move-ing" (as one from <utility> one by one or as from <algorithm> by range), so that all the source's elements remained empty and it will require just w.clear(); call.

Is it possible to make the operator to recognize the rvalue reference? Say:

T & ::operator += (T &, T &&);

Or is there something else I should want?

Upvotes: 3

Views: 177

Answers (1)

Jonathan Wakely
Jonathan Wakely

Reputation: 171413

Yes, that will work, but T is not a type so you can't write the operator like that. T is a template, so the operator would need to be something like

template<typename U>
  T<U>& operator+=(T<U>&, T<U>&&);

A possible implementation would be:

template<typename U>
  T<U>& operator+=(T<U>& lhs, T<U>&& rvalue)
  {
    std::move(rvalue.begin(), rvalue.end(), std::back_inserter(lhs));
    rvalue.clear();
    return lhs;
  }

And overloaded for lvalues:

template<typename U>
  T<U>& operator+=(T<U>& lhs, const T<U>& lvalue)
  {
    std::copy(lvalue.begin(), lvalue.end(), std::back_inserter(lhs));
    return lhs;
  }

To make this work with any type (which I consider a bad idea, it should be constrained to only match the types you want) try this:

template< class T, class U >
  inline
  typename std::enable_if< std::is_lvalue_reference< U >::value, T& >::type
  operator += (T& lhs, U&& lvalue)
  { /* copy from lvalue */ }

template< class T, class U >
  inline
  typename std::enable_if< !std::is_lvalue_reference< U >::value, T& >::type
  operator += (T& lhs, U&& rvalue)
  { /* move from rvalue */ }

Upvotes: 4

Related Questions