Accept lvalue ref or rvalue ref

I want to write some functions that take Object

as one of their arguments regardless of the lvalue or rvalue ref, but definitely not by value and definitely only Object

. I seem to have two options:

void foo(Object& o) {
    // stuff
}

void foo(Object&& o) { foo(o); } // this is fine for my use-case

      

Or using universal links:

template <typename T, typename U>
using decays_to = typename std::is_same<std::decay_t<T>, U>::type;

template <typename T>
std::enable_if_t<decays_to<T, Object>::value>
foo(T&& o) 
{
    // same stuff as before
}

      

But the first option involves writing twice as many functions as I need, and the second option is to write a confusion of template material that seems overkill to me (I sort of read that I take anything for o

- oh just kidding, really simple Object

).

Is there a better way to solve this problem, or am I just really stuck depending on which one I feel the least?

+3


source to share


2 answers


The typical way to accept both lvalues ​​and r values ​​is to create a function that takes a reference constant. This means that you cannot call non-const functions on an object, but if you want to pass r values, such as temporary, then calling non-const functions does not necessarily make sense.



+4


source


There is a difference between your two implementations. The former recognizes anything convertible to Object

, Object&&

or Object&

. The second will only allow Object

things that inherit from it in rvalue or lvalue form (and reject const Object

s, like the first).

We can add a helper object:

template<class T>
struct l_or_r_value {
  T& t;
  l_or_r_value( T&& t_ ):t(t_) {}
  l_or_r_value( T& t_ ):t(t_) {}
  operator T&(){ return t; }
  T* operator->(){ return &t; }
  T& operator*(){ return t; }
  T& get(){ return t; }
};

      

then we can write:

void foo(l_or_r_value<Object> o)

      

and we get behavior very close to your second solution, without the mumbo jumbo pattern at the point of the call. You need to access *o

and o->

or execute Object& o = o_;

to get the original link.



This doesn't seem like the first solution, because C ++ doesn't bind the two custom conversions.

Proposing concepts will add the ability to say, "I'll take something here while this is Object

" with a more concise syntax.

Another approach would be to just take Object&

and use:

tepmlate<class T>
T& lvalue( T&& t) { return t; }

      

to convert rvalues ​​to lvalues ​​when you need it (you could also call it unmove

cute)

+6


source







All Articles