为什么自动返回类型在此示例中丢失了移动语义?

NoS*_*tAl 6 c++ templates auto c++17

我正在观看视频,其中Nicolai说自动失去移动语义为此示例:

template<typename Callable, typename... Args>
auto call(Callable&& op, Args&&... args) {
return std::invoke(std::forward<Callable>(op), std::forward<Args>(args)...);
}
Run Code Online (Sandbox Code Playgroud)

我在想:

  1. 这是为什么?

  2. 在这个例子中确实保证了 RVO的启动吗?如果是这样,有什么担心搬家的?

Sto*_*ica 8

我认为Nicolai可能只是把它说得好一点.

返回时auto,函数返回一个(将推导出的类型).如果std::invoke返回纯rvalue或xvalue,那么当然call会相应地构造结果(如果可能的话,通过移动).在这个意义上,我们不"失去移动语义".

但是当我们按值返回时,需要创建该值对象.它可以通过移动创建,并且在某些情况下(这里不存在)可以省略它,但必须创建它.保证副本省略不允许我们删除创建此对象.

如果std::invoke给我们一个xvalue(一个rvalue引用的东西),这可能是非常浪费的.我们为什么要构造一个返回它的对象?

这就是为什么一两张幻灯片后他说我们应该回来的原因decltype(auto).扣除规则将保留调用的值cateogry std::invoke:

  1. 如果它返回一个值,我们就不会变坏.我们自己call将返回一个值(它可以通过移动返回值来创建std::invoke).

  2. 如果std::invoke返回一个lvalue(X&)或一个xvalue(X&&),它将按原样返回,而不会通过复制或移动创建另一个对象.