【发布时间】:2017-02-06 01:46:58
【问题描述】:
假设我想要一个函数foo 以左值或右值引用作为参数。
我可以将它分成两个重载,分别采用左值和右值引用。
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
}
它确实有效,但非常冗长。我可以使用模板对其进行改进。
template<typename T>
void foo(T &&a) { /*some impl*/ }
int main(){
int a;
foo(a); // lvalue, T = int&
foo(1); // rvalue, T = int
}
对于二元函数,模板需要采用两个模板参数。
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
}
这是要走的路吗?有没有更好的办法?
我几乎没有任何使用 cpp 的经验,但我需要做这些技巧来简单地说“不要复制传递的参数”,这似乎很可疑。
我正在使用 gcc 5.4.0 和 -std=c++11。
-- 更新 1--
我在使用streams 库range(T&& lower, T&& upper) 方法时提出了这个问题,该方法同时采用T&& 参数。我可以将lvalue 或rvalue 参数都传递给函数,但这使我无法将0 和some_var 作为参数传递。无论作者为什么函数采用T&& 参数,我想知道是否有一种方法可以扩展声明以采用混合的左值/右值参数而不牺牲作者想要实现的任何目标。
-- 更新 2--
如果参数是只读的const &可以使用(@RichardCritten)。
当您想修改/返回参数而不复制时,您可以使用模板或@Yakk 解决方案。
@Yakk 的解决方案在您声明一个接受多个参数的函数时似乎更好。
例如,如果一个函数采用两个 int l/r-value 引用参数并使用模板返回 int 引用会导致签名混乱。
template<typename T1, typename T2>
int& foo(T1 &&a, T2 &&b) {
a += b;
return a;
}
虽然@Yakk 解决方案提供了一个非常优雅的解决方案。
int& foo(any_ref<int> a, any_ref<int> b) {
a += b;
return a;
}
【问题讨论】:
-
练习的意义何在?为什么你不能让一个函数以老式的方式通过值或通过 const 引用来获取参数?
-
如果您不需要更改参数的值,只需使用
T const & -
这个问题通常与一个XY问题有关,也许你可以更详细地描述一下导致你问这个问题的情况
-
@IgorTandetnik @M.M 我在使用streams 库
range(T&& lower, T&& upper)方法时提出了这个问题,该方法同时采用右值引用参数,这使我无法通过例如0和@987654346 @ 作为参数。 -
您链接到的基本原理的代码使用通用引用。这与您关于
int&&的问题的实际内容非常不同,int&&不是通用参考。T&&(其中 T 是模板参数)绑定到左值,但int&&没有。更新中的内容应该是之前所有内容的单独问题(即如何修改此range函数模板以接受(0, some_var))