在C++标准库中,std::apply的实现如下:
constexpr decltype(auto) _Apply_impl(_Callable&& _Obj, _Tuple&& _Tpl, index_sequence<_Indices...>) noexcept(
noexcept(_STD invoke(_STD forward<_Callable>(_Obj), _STD get<_Indices>(_STD forward<_Tuple>(_Tpl))...))) {
return _STD invoke(_STD forward<_Callable>(_Obj), _STD get<_Indices>(_STD forward<_Tuple>(_Tpl))...);
}
在表达式
_STD get<_Indices>(_STD forward<_Tuple>(_Tpl))...
中,std::get
被调用的次数与元组的长度相同。但是,每次调用 std::get
时,都会相应调用 std::forward.
转发右值时,std::forward
相当于 std::move
,这意味着对 std::move
对象多次调用 _Tpl
。这似乎可能是无效的。有人可以帮助解释我的担忧吗?非常感谢。
我尝试搜索各种资源,但找不到我正在寻找的答案。从定义开始也没有说服我。
意味着对 _Tpl 对象多次调用 std::move。这似乎可能无效。
是的,元组上有多个对
std::move
的调用。但这本身并不是无效的。
通常,将带有
std::move
的对象传递给函数是对该函数的承诺,即调用者在调用后不会依赖该对象的状态,但在某些情况下,函数向调用者做出更强的承诺.
例如
std::unique_ptr
承诺在调用其移动构造函数或移动赋值后,传递的对象将处于空状态。
对于
std::get
来说,更准确地知道它会做什么:除了返回对元组中所请求元素的引用之外,它不会执行任何操作。并且根据元组是作为右值还是左值传递,在与元素的类型组合时,它还会根据需要返回左值或右值引用。
因此,
std::get
实际上不会修改元组的状态,并且包扩展(顺便说一句,这不是折叠表达式。)将产生一个对元组每个元素的引用的列表,可能作为左值或右值,但同一个对象永远不会有两个右值。因此,当将引用传递给被调用的函数时,不存在与通用 double-std::move
s 等效的问题。