右值引用匹配(完全转发示例)
rvalue reference matching (perfect forwarding example)
我对以下完美的转发函数感到困惑,其中模板参数T
可以匹配右值或左值引用:
template<typename T>
void foo(T&& t){
T::A; // intended error to inspect type
}
int main(){
std::vector<int> a;
std::vector<int> && b = std::move(a);
foo(b); // T is std::vector<int> &
foo(std::move(a)); // T is std::vector<int>
}
我不明白为什么foo
中T
的模板参数演绎在这两种情况下有如此大的不同?t
的根本区别是什么?重要的是,foo
的功能类型是什么?
std::move(a)
返回一个右值引用,而b
已经是一个右值引用(但是有一个名称)。
是否正确,b
的类型是对std::vector<int>
的右值引用,但就我的理解而言,它有一个名称,因此被认为是函数main中的左值?
有谁能解释一下吗:-)
当&&与模板一起使用。
template <class T>
void func(T&& t) {
}
"时,,出现在类型推断上下文中,T&&获得特殊的意思。当func被实例化时,T取决于参数是否传递给func的是左值或右值。如果它是U型的左值,T被演绎为U&如果是右值,则T被演绎为U:"
func(4); // 4 is an rvalue: T deduced to int
double d = 3.14;
func(d); // d is an lvalue; T deduced to double&
float f() {...}
func(f()); // f() is an rvalue; T deduced to float
int bar(int i) {
func(i); // i is an lvalue; T deduced to int&
}
同时,引用折叠规则也是一个很好的选择。
看看这个很好的解释:
完全转发
如果考虑函数的签名,则参数的类型是T&&
。在第二个示例中,T
被推导为vector<int>
,这意味着函数的参数类型是vector<int>&&
。所以你仍然在传递(右值)引用
在另一种情况下,您将T
推断为vector<int>&
。所以参数的类型是vector<int> & &&
…或者应该是,但是引用引用是不允许的。引用崩溃接管,任何涉及左值引用的双引用都变成左值引用。所以你传递的是左值引用
对于b来说,这是一个众所周知的右值引用问题。本质上,b的类型是右值引用,但b本身仍然具有左值的值类别。这样想:b本身是一个变量,它必须存在于堆栈的某个地方,并且有一个地址。所以它是左值。这正是在需要转发参数时调用std::forward的方式。如果您不这样做,那么它们将始终作为左值参数转发。
我非常推荐这篇Scott Meyers的文章:https://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers。仔细阅读!
是否正确,
b
的类型是对std::vector<int>
的右值引用,但就我的理解而言,它有一个名称,因此被认为是函数main中的左值?
是的,正是这样。如果考虑一下右值引用函数的参数,这就更有意义了:调用者指定函数可以对它得到的对象做任何它想做的事情。所以在函数体内部,为了确保代码可以对它做任何想做的事情,参数应该被视为左值。同样的参数也可以用于其他右值引用,包括示例中的b
,尽管范围较小。
表达式 a
和b
都是左值,表达式std::move(a)
是右值。
形参T
的演绎使用了特殊的引用折叠规则,因此t
的类型要么是左值引用,要么是右值引用,以绑定到函数调用实参。
- 正在折叠转发引用
- C++ 何时使用常量引用而不是转发引用
- 模板模板参数和转发引用
- 常量转发引用给出错误 C2440:"正在初始化":无法从"常量标准::字符串"转换为"常量标准::字符串 &&"
- 具有右值引用,而不是使用可变参数模板转发引用
- 自定义类型转换运算符在转发引用上调用时不起作用(当对象按值传递时有效)
- 结构化绑定和转发引用是否混合良好?
- 如何声明接受转发引用并返回引用或副本的函数模板
- 间接转发引用
- 为什么调用转发引用构造函数而不是复制构造函数?
- 为什么 std::get 没有一个接受转发引用的签名
- 对 std::Optional 的转发引用构造函数的约束
- 为什么在这种情况下转发引用不起作用?
- 为什么 std::转发是转发引用所必需的
- 将一包转发引用包装成元组
- 涉及在接口中转发引用的重载
- 将转发引用作为lambda捕获传递
- 是否可以在没有类型推断的情况下实现类似转发引用的行为
- 使用确定类型转发引用行为
- 显式模板实例化和转发引用