- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我发现自己没有完全理解std::move()
的逻辑。
起初,我搜索了一下,但似乎只有关于如何使用 std::move()
的文档,而不是它的结构如何工作。
我的意思是,我知道模板成员函数是什么,但是当我查看 VS2010 中的 std::move()
定义时,它仍然令人困惑。
std::move() 的定义如下。
template<class _Ty> inline
typename tr1::_Remove_reference<_Ty>::_Type&&
move(_Ty&& _Arg)
{ // forward _Arg as movable
return ((typename tr1::_Remove_reference<_Ty>::_Type&&)_Arg);
}
首先对我来说很奇怪的是参数 (_Ty&& _Arg),因为当我像下面这样调用函数时,
// main()
Object obj1;
Object obj2 = std::move(obj1);
基本上等于
// std::move()
_Ty&& _Arg = Obj1;
但正如您已经知道的,您不能直接将 LValue 链接到 RValue 引用,这让我认为它应该是这样的。
_Ty&& _Arg = (Object&&)obj1;
然而,这是荒谬的,因为 std::move() 必须适用于所有值。
所以我想要完全理解它是如何工作的,我也应该看看这些结构。
template<class _Ty>
struct _Remove_reference
{ // remove reference
typedef _Ty _Type;
};
template<class _Ty>
struct _Remove_reference<_Ty&>
{ // remove reference
typedef _Ty _Type;
};
template<class _Ty>
struct _Remove_reference<_Ty&&>
{ // remove rvalue reference
typedef _Ty _Type;
};
不幸的是,它仍然令人困惑,我不明白。
我知道这都是因为我缺乏关于 C++ 的基本语法技能。我想知道这些是如何彻底工作的,并且我可以在互联网上获得的任何文件都将受到欢迎。 (如果你能解释一下,那也太棒了)。
最佳答案
我们从 move 函数开始(我稍微清理了一下):
template <typename T>
typename remove_reference<T>::type&& move(T&& arg)
{
return static_cast<typename remove_reference<T>::type&&>(arg);
}
让我们从更简单的部分开始——即使用右值调用函数时:
Object a = std::move(Object());
// Object() is temporary, which is prvalue
我们的 move
模板被实例化如下:
// move with [T = Object]:
remove_reference<Object>::type&& move(Object&& arg)
{
return static_cast<remove_reference<Object>::type&&>(arg);
}
由于 remove_reference
将 T&
转换为 T
或 T&&
转换为 T
,并且Object
不是引用,我们的最终函数是:
Object&& move(Object&& arg)
{
return static_cast<Object&&>(arg);
}
现在,您可能想知道:我们还需要类型转换吗?答案是:是的,我们愿意。原因很简单;命名右值引用被视为左值(标准禁止从左值到右值引用的隐式转换)。
当我们使用左值调用 move
时会发生以下情况:
Object a; // a is lvalue
Object b = std::move(a);
以及对应的move
实例化:
// move with [T = Object&]
remove_reference<Object&>::type&& move(Object& && arg)
{
return static_cast<remove_reference<Object&>::type&&>(arg);
}
同样,remove_reference
将 Object&
转换为 Object
,我们得到:
Object&& move(Object& && arg)
{
return static_cast<Object&&>(arg);
}
现在我们进入棘手的部分:Object& &&
是什么意思,它如何绑定(bind)到左值?
为了实现完美转发,C++11标准提供了引用折叠的特殊规则,如下:
Object & & = Object &
Object & && = Object &
Object && & = Object &
Object && && = Object &&
如您所见,在这些规则下,Object& &&
实际上意味着 Object&
,它是允许绑定(bind)左值的普通左值引用。
最终的功能是:
Object&& move(Object& arg)
{
return static_cast<Object&&>(arg);
}
这与之前使用 rvalue 的实例化没有什么不同——它们都将其参数转换为 rvalue 引用,然后返回它。不同之处在于第一个实例化只能与右值一起使用,而第二个实例化与左值一起使用。
为了解释为什么我们需要更多remove_reference
,让我们试试这个函数
template <typename T>
T&& wanna_be_move(T&& arg)
{
return static_cast<T&&>(arg);
}
并用左值实例化它。
// wanna_be_move [with T = Object&]
Object& && wanna_be_move(Object& && arg)
{
return static_cast<Object& &&>(arg);
}
应用上面提到的引用折叠规则,你可以看到我们得到的函数不能作为 move
使用(简单地说,你用左值调用它,你得到左值)。如果有的话,这个函数就是恒等函数。
Object& wanna_be_move(Object& arg)
{
return static_cast<Object&>(arg);
}
关于c++ - std::move() 如何将值传输到 RValues 中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7510182/
They say Rvalues 的成员也是 Rvalues - 这很有意义。所以这要么是 VC++ 特有的错误,要么是我对右值理解的错误。 拿这个玩具代码: #include #include
(我搜索了[c++]“c++中的函数式编程”一书,只给出了4个不相关的结果。) 我正在阅读来自 Ivan Čukić 的 C++ 函数式编程 , 在第 118 页有一句话我不确定我是否理解。该节是关于
以下代码无法编译。 Clang 给出此错误消息:候选函数不可行:第一个参数没有从“A”到“A &&”的已知转换 这就好像 f() 中的 a 是一个左值。 struct A{}; void g(A&&
假设我有以下对象 class foo { foo() {..} //Constructor foo(const foo& f) {..} //Copy
我最近一直在玩 Rvalue 引用,但遇到了一个奇怪的问题。让我们定义一些名为 Foo 的简单类,其中包含一个 vector : class Foo { public: Foo(std::ve
RValue 引用的堆栈大小是多少? 例如在这样的情况下: struct A { /* ... */ }; A getA() { A temp; return
RValue 引用的堆栈大小是多少? 例如在这样的情况下: struct A { /* ... */ }; A getA() { A temp; return
现在我有一个只有一个构造函数的类 ShaderProgram(std::initializer_list> shaders); 我正在使用引用包装器,因为我没有引用的 initializer_list
我一直在努力理解移动构造函数场景背后发生的事情,但我的脑海中缺少了一些东西。 struct A { int s; A() : s(10) {} A(const A&
我有一个可变模板函数 template inline void ReadStream::decode(ARGS&...args) { internalDecode(args...); } tem
RValues 是不可操作的内存区域,因此像整数这样的文字被认为是 RValues。 常量构成 RValues 吗? const int x = 0; 至少可操作一次。 现在,编译器创建的临时对象也是
“*this 的右值引用”最典型的用例是什么?标准也将其称为成员函数的引用限定符? 顺便说一下,关于这个语言特性有一个非常好的解释 here 。 最佳答案 调用时,每个成员函数都有一个 *this 引
我有一个带有值的 vector : obj={1.0,2.0,3.0, 4.0,5.0,6.0 ,7.0,8.0,9.0,10.0} 假设,在数学上 obj 被划分为三个子 vector : obj=
考虑以下 C++ 代码 template void f (const int x, const int y, Args&&... args) { // Do something } 据我了解,这
考虑以下代码: int three() { return 3; } template class Foo { private: T* ptr; public: void ba
在 clang 的 C++11 status page 中遇到了一个名为“*this 的右值引用”的提议. 我已经阅读了很多关于右值引用的内容并理解了它们,但我认为我对此一无所知。我在网络上也找不到太
我遇到了下面的代码,但我在谷歌上找不到为什么下面的语句是有效的 C++: Base&& b = Derived(); 请解释或给出引用 这是一个示例代码: #include using namesp
在 clang 的 C++11 status page 中遇到了一个名为“*this 的右值引用”的提议. 我已经阅读了很多关于右值引用的内容并理解了它们,但我认为我对此一无所知。我在网络上也找不到太
我遇到了 RValue 不允许隐式转换的问题。我的问题是什么实现更好地“绕过”这个限制? 下面是说明问题的示例代码: template class ITestClass { public: vir
我想知道这怎么可能? template void Test(T&& arg) { arg = 14; } int a = 23; Test(a); 我的问题是函数 Test 需要一个右值类型的
我是一名优秀的程序员,十分优秀!