将多个右值和左值传递给一个函数而不创建重载
passing multiple rvalues and lvalues to a function without creating overloads
假设您正在为客户端库提供一个具有多个引用参数的函数。
为了简单起见,我们假设我们有3个参数,这些参数是对int
的各种引用(因此您可以假设这些常数也将由initializer_list
创建(。
从调用站点,应该可以将临时创建的常量(rvvalue(传递给函数(在这种情况下可以考虑测试代码(,以及传递给另一个实体拥有的对象的实际引用。
到目前为止,我已经提出了以下解决方案:
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;
}
我对所有的解决方案都不完全满意,因为每一个都有缺点。有没有更清洁的替代方案来解决这个问题?
这个问题其实并不简单,但有一些指导方针经过多年的发展,实际上在C++11中没有太大变化。对于以下内容,我们将假设您有一个无副作用、独立的函数(构造函数和某些成员函数的指导方针略有不同(。
我对独立功能的建议是:
- 按值传递基元数据类型(int、double、bool等(
- 通过const引用传递复杂的数据类型(例如const std::vector&(,除非您需要函数中的副本,然后通过值传递
- 如果您的函数是模板化的,请使用const引用(例如const T&(,因为左值和右值都将绑定到const引用
- 如果你的函数是模板化的,并且你打算完善转发,那么就使用转发引用(例如T&&,也称为通用引用(
因此,对于使用整数的示例,我将使用bam
函数:
void bam(int x, int y, int z) { }
Herb Sutter去年在CppCon上发表了一篇有趣的演讲其中包括函数的输入参数:https://www.youtube.com/watch?v=xnqTKD8uD64
关于stackoverflow的另一个有趣的帖子与这个问题有关:正确使用右值参考作为参数
构造函数更新:
构造函数与上述建议的主要区别在于更加强调复制输入并使对象归类所有。二传手也是如此。主要原因是更安全的资源管理(避免数据竞争或访问无效内存(。
这是一个完美的转发问题。避免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
和U
将被推导为vector<int>&&
,而V
将被推断为vector<int>&
。因此,您就拥有了此实现中所需的所有信息。
template<class T>
struct lrvalue {
T&t;
lrvalue(T&in):t(in){}
lrvalue(T&&in):t(in){}
};
取CCD_ 17。问题解决了吗?你可以把它们打扮一下,也许可以继承reference_wrapper
或类似的东西,而不是T&t
。
您也可以在调用时进行投射:
template<class T>
T& lvalue(T&&t){return t;}
template<class T>
T& lvalue(T&t)=delete;//optional
现在,如果您想将foo{}
传递给foo&
,您可以。CCD_ 22。
- 创建一个函数以在输入为负数或零时输出字符串.第一次执行用户定义的函数
- 如何仅为一个函数添加延迟
- 有没有什么方法可以使用一个函数中定义的常量变量,也可以由c++中同一程序中的其他函数使用
- 我需要将多个函数组合为一个函数
- 在C++中声明一个函数时,它需要有函数本身的参数吗
- 如何创建一个函数来计算并返回平均值、最大值和最小值
- 一个函数,用于查找字符串1包含字符串2 c++的次数
- 如何将一个类的函数作为另一个类的另一个函数的参数传递
- 编写一个函数以使用 n 百分比的 CPU 使用率
- 将 N-arg 函数包装到另一个函数中
- 如何封装一个函数,以便它只能由同一类中的一个其他函数调用?
- C++(.cpp文件和.h文件)拆分代码并添加一个函数,提取 - 这很容易吗?
- C++从另一个函数退出函数
- 编写一个函数来删除单链表中的节点(尾部除外),仅授予对该节点的访问权限
- 视觉我希望一个函数在另一个函数C++中进行计算
- C ++如何在原始抽象类中创建一个函数,该函数接受派生类的输入
- 在另一个函数 (c++) 中调用变量
- 如何在另一个函数中使用返回值作为参数?
- 如何包装一个函数以适应另一个函数的所需类型
- 创建一个函数的 Python 绑定,返回指向带有 boost 的向量的指针