C++ 不能为在 lambda 中捕获的承诺移动调用 set_value?

C++ cannot call set_value for promise move-captured in a lambda?

我正在尝试编写一个相当简单的方法 returns 一个未来。 lambda 设定了未来。这是一个最小的例子。实际上,lambda 可能会在不同的线程等中被调用。

#include <future>

std::future<std::error_code> do_something() {
  std::promise<std::error_code> p;
  auto fut = p.get_future();
  auto lambda = [p = std::move(p)] {
    std::error_code error;
    p.set_value(error);
  };
  lambda();
  return std::move(fut);
}

int main() { return do_something().get().value(); }

出于某种原因,我遇到了类型错误。 VSCode 智能感知说:

no instance of overloaded function "std::promise<_Ty>::set_value [with _Ty=std::error_code]" matches the argument list and object (the object has type qualifiers that prevent a match) -- argument types are: (std::remove_reference_t<std::error_code &>) -- object type is: const std::remove_reference_t<std::promise<std::error_code> &>

并且 MSVC 编译器说:

error C2663: 'std::promise<std::error_code>::set_value': 2 overloads have no legal conversion for 'this' pointer

VS Code 报错我实在是看不懂。是说它认为error是一个const promise<error_code>吗?如何在 lambda 捕获中 moved 的承诺上正确调用 set_value

默认情况下,lambda 将所有捕获的值(非引用)存储为 const 值,您无法修改它们。但是lambda支持关键字mutable,你可以这样添加:

[/*...*/](/*...*/) mutable { /*...*/ }

这将允许 lambda 的内部主体修改其所有值。

如果由于某种原因您无法使用 mutable,那么您可以使用其他解决方法:

[/*...*/, p = std::make_shared<ClassName>(std::move(p)), /* ... */](/*...*/) {/*...*/}

换句话说,如果您愿意,可以将移动的值包装到 std::shared_ptr, you can also use std::unique_ptr 中。

包装到共享指针解决了这个问题,因为共享指针(也是唯一的)允许修改它的底层对象值,即使指针本身是 const.

不要忘记在 lambda 的主体内将 p 取消引用为指针,换句话说,如果您使用 p.SomeMethod(),现在您必须使用 p->SomeMethod()(与-> 运算符)。