Suppose I want to have a function foo
taking either lvalue or rvalue reference as the parameter.
I could break it into two overloads taking lvalue and rvalue references.
void foo(int& a){/*some impl*/} // lvalue ref
void foo(int&& a){foo(a);} // rvalue ref
int main(){
int a;
foo(a); // lvalue
foo(1); // rvalue
}
It does work but is pretty verbose. I could improve it using templates.
template<typename T>
void foo(T &&a) { /*some impl*/ }
int main(){
int a;
foo(a); // lvalue, T = int&
foo(1); // rvalue, T = int
}
For a binary function the template would need to take two template parameters.
template<typename T1, typename T2>
void foo(T1 &&a, T2 &&b) { /*some impl*/ }
int main(){
int a;
foo(a, a); // (lvalue, lvalue), T1 = int&, T2 = int&
foo(1, 1); // (rvalue, rvalue), T1 = int, T2 = int
foo(1, a); // (rvalue, lvalue), T1 = int, T2 = int&
foo(a, 1); // (lvalue, rvalue), T1 = int&, T2 = int
}
Is it the way to go? Is there any better way?
I have hardly any experience using cpp but it seems suspicious that I need to do such tricks to simply say "do not make copies of passed parameters".
I am using gcc 5.4.0
with -std=c++11
.
-- UPDATE 1 --
I came up with the question when I was using streams library range(T&& lower, T&& upper)
method which takes both T&&
parameters. I can pass both lvalue
or rvalue
parameters to the function but it makes me unable to pass for example 0
and some_var
as parameters. Whatever is the author's reasons for the function taking T&&
parameters I was wondering if there is a way to extend the declaration to take mixed lvalue/rvalue parameters without sacrificing whatever the author wanted to achieve.
-- UPDATE 2 --
If the parameter is read-only const &
can be used (@RichardCritten).
When you want to modify/return the parameter without copying you can use either templates or @Yakk solution.
@Yakk solution seems better when you declare a function that takes multiple parameters.
For example, if a function takes two int l/r-value reference parameters and returns int reference using templates leads to a messy signature.
template<typename T1, typename T2>
int& foo(T1 &&a, T2 &&b) {
a += b;
return a;
}
While @Yakk solution gives a pretty elegant one.
int& foo(any_ref<int> a, any_ref<int> b) {
a += b;
return a;
}