为什么 C++23 string::resize_and_overwrite 调用操作作为右值?

Why does C++23 string::resize_and_overwrite invoke operation as an rvalue?

为了提高向std::string写入数据的性能,C++23特地引入了resize_and_overwrite() for std::string. In [string.capacity],标准是这样描述的:

template<class Operation>
constexpr void resize_and_overwrite(size_type n, Operation op);
  1. Let

    o = size() before the call to resize_and_overwrite.

    k be min(o, n).

    p be a charT*, such that the range [p, p + n] is valid and this->compare(0, k, p, k) == 0 is true before the call. The values in the range [p + k, p + n] may be indeterminate [basic.indet].

    OP be the expresion std::move(op)(p, n).

    r = OP.

[...]

  1. Effects: Evaluates OP, replaces the contents of *this with [p, p + r), and invalidates all pointers and references to the range [p, p + n].

但是我发现这个函数在调用它之前会使用std::moveop转换成一个右值,这意味着我们不能传入一个只重载了左值的可调用对象operator() (demo):

#include <string>

int main() {
  struct Op {
    int operator()(char*, int) &;
    int operator()(char*, int) && = delete;
  } op;
  std::string s;
  s.resize_and_overwrite(42, op); // ill-formed
}

这个行为看起来有点奇怪,但是由于这个改变是在 论文的last edition,明显是故意的

那么,这背后的考虑是什么? op 必须作为右值调用的强制要求有什么好处吗?

op 在被销毁之前只被调用一次,因此将其作为右值调用允许对其进行任何 && 重载以重用它可能持有的任何资源。

可调用对象道德上的一个xvalue——它是“过期的”,因为它在调用后立即被销毁。如果您专门将可调用对象设计为仅支持作为左值调用,那么库很乐意通过阻止它工作来提供帮助。