假设您正在为客户端库提供具有多个引用参数的函数。
为了简单起见,我们假设我们有3个参数,这些参数是对int
的各种引用(所以你可以假设,这些常量也会由initializer_list
创建)。
从调用站点,应该可以将临时创建的常量(rvalue)传递给函数(在这种情况下考虑测试代码)以及对另一个实体拥有的对象的实际引用。
到目前为止,我已经提出了以下解决方案:
void bar(int &x, int &y, int &z) { }
// use a template wrapper to turn rvalues into lvalues.
template <typename T, typename U, typename V>
void foo(T &&t, U &&u, V &&v) {
bar(t,u,v);
}
// create a humongous amount of overloads
void baz(int &&x, int &y, int &z) { }
void baz(int &x, int &&y, int &z) { }
void baz(int &&x, int &&y, int &z) { }
void baz(int &x, int &y, int &&z) { }
void baz(int &&x, int &y, int &&z) { }
void baz(int &x, int &&y, int &&z) { }
void baz(int &&x, int &&y, int &&z) { }
// claim ownership of the objects and create temporaries
void bam(int x, int y, int z) { }
int main() {
int i = 1;
foo(i,2,3);
foo(2,i,3);
foo(2,3,i);
bar(i,2,3); // doesn't compile
bar(2,i,3);
bar(2,3,i);
baz(i,2,3); // requires 8 overloads
baz(2,i,3);
baz(2,3,i);
return 0;
}
我并不完全满意所有解决方案,因为每个解决方案都有缺点。有没有更清洁的替代方案来解决这个问题?
答案 0 :(得分:1)
这是完美的转发问题。避免baz
的8次重载的方法是使用所谓的通用引用:
template <typename T, typename U, typename V>
void baz(T &&t, U &&u, V &&v) { }
在上文中,t
,u
和v
忠实地复制了参数的r / l值。例如,假设您原来的预期功能是:
void baz(vector<int> &t, vector<int> &u, vector<int> &v) { }
和其他7个重载。使用模板化版本时,如果您致电baz(a,b,c)
其中a
和b
是左值,而c
不是T
和{{1} } U
将被推断为vector<int>&&
,而V
将推断为vector<int>&
。因此,您可以获得此实现中所需的所有信息。
答案 1 :(得分:1)
这个问题实际上并非无足轻重,但有些指导方针已经发展多年,并且实际上并没有因C ++ 11而发生太大变化。对于以下内容,我们假设您具有无副作用的独立函数(指南对于构造函数和某些成员函数略有不同)。
我建议的独立功能是:
因此,对于使用整数的示例,我将使用bam
函数:
void bam(int x, int y, int z) { }
Herb Sutter去年在CppCon上发表了一篇有趣的演讲 其中包括函数的输入参数: https://www.youtube.com/watch?v=xnqTKD8uD64
有关此问题的另一篇关于stackoverflow的有趣帖子: Correct usage of rvalue references as parameters
构造函数更新:
构造函数与上述建议的主要区别在于更强调复制输入并使对象拥有该类。对于制定者来说也是如此。主要原因是更安全的资源管理(避免数据争用或访问无效内存)。
答案 2 :(得分:1)
template<class T>
struct lrvalue {
T&t;
lrvalue(T&in):t(in){}
lrvalue(T&&in):t(in){}
};
取lrvalue<int>
。问题解决了?你可以装扮它们,也许继承自reference_wrapper
或某些而不是T&t
。
您还可以在致电时投票:
template<class T>
T& lvalue(T&&t){return t;}
template<class T>
T& lvalue(T&t)=delete;//optional
现在,如果您想将foo{}
传递给foo&
,您可以。 lvalue(foo{})
。