(Reply) [entries|reading|network|archive]
simont

[ userinfo | dreamwidth userinfo ]
[ archive | journal archive ]

[personal profile] crazyscot Sat 2019-03-09 22:34
std::forward<T>(x) is pretty much exactly "preserve the lvalueosity of x" - it is defined as static_cast<T&&>(x). https://stackoverflow.com/questions/3582001/advantages-of-using-forward goes into detail.

You need to be careful with mixing and matching rvalues and lvalues in this way. In the general case, what do you want to get out - an rvalue or an lvalue? If it's an lvalue, you'd better be passing in a pair of lvalues - you can't expect to be able to write to an rvalue.

If - as your function definition implies - you only wanted an rvalue, well, surely you only need to be passing by value in the first place? (Though you might be dealing with expensive objects and want to have std::move semantics available for efficiency, so you maybe want to support that with rvalue references.)

Messing around, I came to this excrescence. At the cost of writing the template code three times (wasn't that what templates were supposed to save us from?!) you can cope with mix-and-match inputs - but even then, assigning to something that might return an rvalue is quite rightly an error:


#include <iostream>
#include <utility>

template<typename T>
T&& rvmax(T& u, T&& v) { return std::forward<T>(u>v ? u : v); }

template<typename T>
T&& rvmax(T&& u, T& v) { return std::forward<T>(u>v ? u : v); }

template<typename T>
T&& rvmax(T&& u, T&& v) { return std::forward<T>(u>v ? u : v); }

int main()
{
int var1 = 100, var2 = 200;
int test = std::move(rvmax(101, var1));
int test2 = std::move(rvmax(var1,4242));
rvmax(var1, var2) = 999;
// rvmax(42, var1) = 999; // error: using xvalue (rvalue reference) as lvalue
std::cout << var1 << " " << var2 << " " << rvmax(199,var1) << std::endl;
}


Then, in a flash of inspiration, I realised that templates do in fact save the day if you decouple the type deductions. As long as your two inputs are the same type - or sufficiently compatible that '>' is defined and you can return one as if it was the other - you can replace the triply-defined template with this single one:

template<typename T, typename Tp>
T&& rvmax(T&& u, Tp&& v) { return std::forward<T>(u>v ? u : v); }

Link Read Comments
Reply:
This account has disabled anonymous posting.
If you don't have an account you can create one now.
HTML doesn't work in the subject.
More info about formatting