Here are two functions. They are asynchronous functions. Both have a callback function parameter cb
.
The function template_cb
's callback type is template Cb
.
The function std_function_cb
's callback type is std::function<void()>
.
namespace as = boost::asio;
// BEGIN 3rd party code (I can't modify)
inline
void std_function_cb(as::io_context& ioc, std::function<void()> cb) {
// pseudo implementation
as::post(ioc, std::move(cb));
}
// END 3rd party code (I can't modify)
Let's assume we can't modify the functions.
Now, I want to adapt the functions to Boost.Asio CompletionToken. See https://www.boost.org/doc/libs/1_80_0/doc/html/boost_asio/reference/async_compose.html
The current version of the functions can only be used with callback functions. But if I adapt the function to the CompletionToken, they can be worked with not only callback functions, but also futures and coroutines. It flexible.
The following code demonstrates adapted function async_call
.
int main() {
std::cout << BOOST_VERSION << std::endl;
{
std::cout << "token as callback" << std::endl;
as::io_context ioc;
async_call(
ioc,
[] {
std::cout << "cb called" << std::endl;
}
);
ioc.run();
}
{
std::cout << "token as future" << std::endl;
as::io_context ioc;
std::future<void> f = async_call(ioc, as::use_future);
std::thread th {[&] { ioc.run(); }};
f.get();
std::cout << "future unblocked" << std::endl;
th.join();
}
}
So I tried it.
I wrote the following adaptation code. But I got compile error.
You can see the complete code and compile error message at https://godbolt.org/z/qxYfGM7hd
It seems that the error is caused by self
is movable but not copyable. However, std::function
requires copyable.
struct async_impl {
as::io_context& ioc_;
enum { first, second } state_ = first;
template <typename Self>
void operator()(Self& self) {
switch (state_) {
case first:
state_ = second;
std_function_cb(ioc_, std::move(self));
break;
case second:
self.complete();
break;
}
}
};
template <typename CompletionToken>
auto async_call(
as::io_context& ioc,
CompletionToken&& token
)
->
typename as::async_result<
typename std::decay<CompletionToken>::type,
void()
>::return_type {
return
as::async_compose<
CompletionToken,
void()
>(async_impl{ioc}, token);
}
I've checked move_only_function and unique_function. I guess they work well with CompletionToken adaptor code.
However, I can't modify std_function_cb
parameter type.
Is there any way to solve this problem?