Home > Mobile >  C cannot call set_value for promise move-captured in a lambda?
C cannot call set_value for promise move-captured in a lambda?

Time:11-19

I'm trying to write a fairly simple method that returns a future. A lambda sets the future. This is a minimal example. In reality the lambda might be invoked in a different thread, etc.

#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(); }

For some reason I get a type error. VSCode intellisense says:

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> &>

And MSVC compiler says:

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

I really don't understand the VS Code error. Is it saying that it thinks error is a const promise<error_code>? How do I correctly call set_value on a promise which was moved inside a lambda's capture?

CodePudding user response:

By default lambda stores all its captured values (non-references) as const values, you can't modify them. But lambda supports keyword mutable, you can add it like this:

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

This will allow inside body of a lambda to modify all its values.

If for some reason you can't use mutable, then you can use other work-around:

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

In other words wrap your moved value into std::shared_ptr, you can also use std::unique_ptr if you like.

Wrapping into shared pointer solves the problem, because shared pointer (unique also) allows to modify its underlying object value even if pointer itself is const.

Don't forget inside the body of a lambda to dereference p as a pointer, in other words if you used p.SomeMethod(), now you have to use p->SomeMethod() (with -> operator).

  • Related