“auto v = f()”和“auto && v = f()”有什么区别?
#include <vector>
using namespace std;
vector<int> f()
{
return{};
}
// Update: Below is not compilable
void g(vector<int>)
{}
// Update: Below is the my initial intent.
/*
void g(const vector<int>&)
{}
*/
void g(vector<int>&&)
{}
int main()
{
auto v1 = f();
auto&& v2 = f();
g(forward<vector<int>>(v1));
g(forward<vector<int>>(v2));
}
请问C++ 11的保证g(forward<vector<int>>(v1))
会打电话f(vector<int>)
或f(const vector<int>&)
和g(forward<vector<int>>(v2))
将调用f(vector<int>&&)
?“auto v = f()”和“auto && v = f()”有什么区别?
区别在于v1
是一个向量,而v2
是一个向量的右值引用。
超载g
你做的方式是一个非常糟糕的主意。如果参数是cv不合格的右值,那么调用将是不明确的,因为这两个g
都可以接受具有身份转换序列的右值。然而,可以接受的是一个超载取T&
,另一个取T&&
。
如果您想转发f()
的值类别,请不要像您所做的那样将其复制/移动到v1
。这破坏了价值类别信息。 v1
将永远是一个左翼。
此外,您没有正确使用std::forward
。在这种情况下,v1
和v2
都将转换为右值引用,并且在重载解析下的行为方式相同。
这里是什么std::forward
的正确用法是这样的:
void g(vector<int>&);
void g(vector<int>&&);
int main() {
auto&& v1 = function_returning_lvalue_vector();
auto&& v2 = function_returning_rvalue_vector();
g(forward<decltype(v1)>(v1)); // calls lvalue overload
g(forward<decltype(v2)>(v2)); // calls rvalue overload
}
_v2是一个右值reference_ ...实际上它不是,见M.M.的答案。 – zett42
@ zett42为了保护这个答案 - 说“v2'是...”是不明确的; v2 *实体*是右值引用,但v2 *表达式*是左值。我同意第一段可以稍微澄清一点,因为对于那些不了解这种区别的人来说,这没什么意义。 –
有叫返回值有回传值功能相关联的对象。 f()
的返回值是vector<int>
。
在C++ 11和C++ 14,其中f()
通过返回值:
-
auto v1 = f();
初始化vector<int>
,这将称为v1
,从返回值,使用复制/移动的构造。这是一个复制elision上下文。 -
auto&& v2 = f();
使名称v2
指定返回值,并且延长返回值的生存期。
如果编译器确实执行copy-elision,那么这两个代码具有相同的效果。从C++ 17开始,所谓的“保证副本删除”,这两个代码将是相同的。 “相同”,除了decltype(identifier)
的结果以外,我的意思是在所有方面都是相同的。
你的两个g
调用没有区别。在这两种情况下,参数都是std::vector
类型的左值。 表达式v1
和v2
不“记住”它们是否最初是返回值对象。
std::forward
只有在给定模板参数时才有用,该模板参数是完美转发推演的结果(因此可能是参考类型)。
建议使用decltype
。 decltype(identifier)
是一种特殊情况,在应用auto
扣除之后,确实记得标识符已被声明。
-
decltype(v1)
是vector<int>
-
decltype(v2)
是vector<int> &&
但是现在我们有了:
-
std::forward<decltype(v1)>
是vector<int> &&
-
std::forward<decltype(v2)>
是vector<int> &&
所以你还是不区分两种不同形式的g
。
事实上,在评论中指出,这是不可能叫g
可言。每个电话都会模糊不清。在重载解析中,直接引用绑定是一种身份转换; T
类型的xvalue参数与T&&
参数T
相等。 (类似地,类型T
的左值参数将与参数T
相同,与T&
相同)。
这将有可能超载g
有左值与右值重载。但是,您还需要更改v1
的初始化:
void g(vector<int> const &) {}
void g(vector<int> &&) {}
// ...
auto const& v1 = f();
auto&& v2 = f();
g(std::forward<decltype(v1)>(v1));
g(std::forward<decltype(v2)>(v2));
这不能在我的机器上编译。调用g()是不明确的。所以这个问题实际上应该是为什么会发生。 – zett42
我强烈建议恢复编辑,您的更改会使现有答案无效。或者在编辑中发布附录,而不更改原始代码 –
@ M.M,根据您的建议更新了文章。 – xmllmx