声明一个可以使用右值或左值引用的函数的正确方法是什么

What is the proper way to declare a function that can take either rvalue or lvalue reference?

本文关键字:函数 引用 是什么 方法 一个 可以使 声明      更新时间:2023-10-16

假设我想要一个函数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-

当我使用流库range(T&& lower, T&& upper)方法时,我提出了这个问题,该方法同时使用T&&参数。我可以将lvaluervalue参数都传递给函数,但这使我无法将例如0some_var作为参数传递。无论作者使用T&&参数的函数的原因是什么,我想知道是否有一种方法可以在不牺牲作者想要实现的任何目标的情况下,将声明扩展为使用混合的左值/右值参数。

--更新2-

如果参数为只读,则可以使用const &(@RichardCritten)。

当您想在不复制的情况下修改/返回参数时,可以使用模板或@Yakk解决方案。

@当您声明一个接受多个参数的函数时,Yakk解决方案似乎更好。

例如,如果一个函数使用两个int l/r值引用参数,并使用模板返回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;
}
template<class T>
struct any_ref{
T& t;
any_ref(T&in):t(in){}
any_ref(T&&in):any_ref(in){}
any_ref(any_ref const&)=default;
any_ref& operator=(any_ref const&)=default;
~any_ref()=default;
operator T&()const&{return t;}
operator T&&()&&{return std::move(t);}// maybe
T& get()const{return *this;}
};

然后:

void foo(any_ref<int>a, any_ref<int>b);

不是模板函数。如果实体想要真正的引用,它可以执行int&a=a_arg;

但实际上,如果您想要一个"可能out"参数,只需使用int&即可。想要将右值作为左值传递的调用者可以写:

templare<class T>
T& as_lvalue(T&&t){return t;}

并抛弃他们的富足。

如果参数是只读引用,请使用const&