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?
source to share
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.
source to share
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)
source to share