以下解决方案是我计划在我自己的应用程序中使用的解决方案。三大特点:
函数/lambdas 是 post_function_use_future() 的参数。要求:函数必须返回 void 以外的值,并且它们必须有零输入参数。注意 SayHello() 现在返回一个 int。
可以使用任何 Asio 上下文,例如 io_context 和 strands。
在撰写本文时,没有弃用的功能。
在主 cpp 文件中:
#include <iostream>
#include <thread>
#include <boost/asio.hpp>
#include "function_return_type.hpp"
template <typename ExecutionContext, typename FuncWithReturnNoArgs>
auto post_function_use_future(ExecutionContext& ctx, FuncWithReturnNoArgs f)
{
using handler_type = typename boost::asio::handler_type
<boost::asio::use_future_t<>, void(boost::system::error_code, return_type_t<FuncWithReturnNoArgs>)>::type;
using Sig = void(boost::system::error_code, return_type_t<FuncWithReturnNoArgs>);
using Result = typename boost::asio::async_result<boost::asio::use_future_t<>, Sig>;
using Handler = typename Result::completion_handler_type;
Handler handler(std::forward<decltype(boost::asio::use_future)>(boost::asio::use_future));
Result result(handler);
boost::asio::post(ctx, [handler, f]() mutable {
handler(boost::system::error_code(), f());
});
return result.get();
}
namespace asio = boost::asio;
int SayHello()
{
std::cout << "Hello!" << std::endl;
return 0;
}
template <typename T>
T GetSum(T a, T b)
{
std::cout << "Adding " << a << " and " << b << std::endl;
return a + b;
}
int main() {
asio::io_context io;
auto wg = asio::make_work_guard(io);
std::thread t{ [&] { io.run(); } };
auto res1 = post_function_use_future(io, SayHello);
res1.get(); // block until return value received.
auto res2 = post_function_use_future(io, []() {return GetSum(20, 14); });
std::cout << res2.get() << std::endl; // block until return value received.
wg.reset();
if(t.joinable()) t.join();
return 0;
}
在 function_return_type.hpp 文件中(非常感谢这个解决方案):
#ifndef FUNCTION_RETURN_TYPE_HPP
#define FUNCTION_RETURN_TYPE_HPP
template <typename F>
struct return_type_impl;
template <typename R, typename... Args>
struct return_type_impl<R(Args...)> { using type = R; };
template <typename R, typename... Args>
struct return_type_impl<R(Args..., ...)> { using type = R; };
template <typename R, typename... Args>
struct return_type_impl<R(*)(Args...)> { using type = R; };
template <typename R, typename... Args>
struct return_type_impl<R(*)(Args..., ...)> { using type = R; };
template <typename R, typename... Args>
struct return_type_impl<R(&)(Args...)> { using type = R; };
template <typename R, typename... Args>
struct return_type_impl<R(&)(Args..., ...)> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args...)> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args..., ...)> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args...) &> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args..., ...) &> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args...) && > { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args..., ...) && > { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args...) const> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args..., ...) const> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args...) const&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args..., ...) const&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args...) const&&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args..., ...) const&&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args...) volatile> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args..., ...) volatile> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args...) volatile&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args..., ...) volatile&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args...) volatile&&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args..., ...) volatile&&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args...) const volatile> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args..., ...) const volatile> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args...) const volatile&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args..., ...) const volatile&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args...) const volatile&&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type_impl<R(C::*)(Args..., ...) const volatile&&> { using type = R; };
template <typename T, typename = void>
struct return_type
: return_type_impl<T> {};
template <typename T>
struct return_type<T, decltype(void(&T::operator()))>
: return_type_impl<decltype(&T::operator())> {};
template <typename T>
using return_type_t = typename return_type<T>::type;
#endif