The following fails (https://godbolt.org/z/qzeqW6eeb):
#include <ppltasks.h>
#include <future>
#include <iostream>
#include <thread>
void third_party_lib_call_that_blocks(std::string message) {
std::cout << message << "\n";
std::this_thread::sleep_for(std::chrono::seconds(1));
}
class nocopy {
public:
explicit nocopy() {}
nocopy(const nocopy& _Other) = delete;
nocopy(nocopy&& _Other) = default;
nocopy& operator=(const nocopy&) = delete;
nocopy& operator=(nocopy&&) = default;
};
int main() {
std::string message = "hello";
nocopy n;
auto t = concurrency::create_task([message = std::move(message), n = std::move(n)]() {
std::cout << "start\n";
third_party_lib_call_that_blocks(message);
std::cout << "end\n";
});
t.wait();
return 0;
}
C:/data/msvc/14.34.31931-Pre/include\ppltasks.h(4544): error C2338: static_assert failed: 'incorrect argument for create_task; must be either a callable object or a task_completion_event'
<source>(30): note: see reference to function template instantiation 'Concurrency::task<Concurrency::details::_BadArgType> Concurrency::create_task<main::<lambda_1>>(_Ty,Concurrency::task_options)' being compiled
with
[
_Ty=main::<lambda_1>
]
Execution build compiler returned: 2
I've narrowed this down to create_task
requiring a copy constructor. Is there a way to work around this? I have a move-only object I need to move into this thread.
The move-only object is provided by a separate library. Specifically, the auto&& self
parameter provided by asio::async_compose
to its lambda, something like:
asio::async_compose<Token, void(std::error_code)>(
[message = std::move(message)](auto&& self) mutable {
concurrency::create_task(
[message = std::move(message), self = std::move(self)]() mutable {
auto ec = third_party_lib_call_that_blocks(std::move(message));
self.complete(ec);
});
},
token, executor_);
If anyone knows of a workaround to turn that self
into a copyable object, I'd take that too. I have no idea what precise type it is and asio docs don't say.