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 move
d 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).