There is an extensive discussion of ideal forwarding in boilerplate functions to ensure that lvalues ββor rvalues ββare effectively passed as parameters to other functions.
However, I cannot find a discussion of the ideal return or, what is the same, the perfect passage. (The related Perfect pass-through question does not completely resolve this.)
Consider the case of a function that changes the range and should return the changed range. We will need two separate functions to effectively address the cases of the lvalue and rvalue arguments:
Of course, including both definitions lead to ambiguity errors, because the second also corresponds to lvalue links.
A motivating example (and using a test) is the following:
#include <iostream> #include <vector> #include <algorithm> std::ostream& operator<<(std::ostream& os, const std::vector<int>& v) { os << "["; for (int i : v) { os << " " << i; } os << " ]\n"; return os; } int main() { std::vector<int> c1{3,4,2,1}; std::cerr << sortr(c1) << sortr(std::vector<int>({7,6,5,8})); }
Is it possible to define both versions of sortr
with one definition of template<typename T>
?
The problem is that declaring the return type as T&&
will only produce the result (after matching with the pattern) in the T&&
or T&
return type, not T
Is it possible to determine the appropriate template function using metaprogramming by return type? Something like the following:
template<typename T> auto sortr(T&& r) -> typename std::conditional<std::is_lvalue_reference<T>::value, T&, T>::type { std::sort(std::begin(r),std::end(r)); return std::forward<T>(r); }
It seems to work, but I'm not sure if it is safe and wise. Any recommendations are appreciated.