为什么 auto return 类型在此示例中丢失了移动语义?

Why does auto return type lose move semantics in this example?

我在看 video Nicolai 说 auto 在这个例子中失去了移动语义:

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

我在想:

  1. 为什么会这样?

  2. guaranteed RVO 是否启动 这个例子?如果是这样,担心搬家有什么意义?

我认为 Nicolai 可以将其表述得更好一些。

当您通过 auto return 时,您的函数 return 是一个 (将推导其类型)。如果 std::invoke return 是纯右值或 x 值,那么 call 的结果当然会相应地构造(如果可能,通过移动)。我们不 "lose move semantics" 从这个意义上说。

但是当我们return按值时,需要创建那个值对象。它可以通过移动创建,并且在某些情况下(which aren't present here)可以省略,但必须创建。有保证的复制省略不允许我们逃避创建这个对象。

如果 std::invoke 给我们返回一个 xvalue(对某物的右值引用),那将是非常浪费的。为什么要构造一个对象来return呢?

这就是为什么一两张幻灯片后他说我们应该 return 到 decltype(auto)。扣除规则将保留调用 std::invoke:

的值类别
  1. 如果它 return 是一个值,我们的情况不会更糟。我们自己的 call 将 return 一个值(它可以通过移动 std::invoke 的 return 值来创建)。

  2. 如果 std::invoke return 是一个左值 (X&) 或一个 x 值 (X&&),那将是 return按原样编辑,无需通过复制或移动创建另一个对象。