Boost::ASIO:如何从 io_service 获取 return 值?
Boost::ASIO: How can I capture return value from io_service?
如何从 boost::asio::io_service
中获取 return 值?是否可以使用一些绑定或任何不涉及重写函数的简单构造?
以下是一个最小的例子。我正在尝试捕获 GetSum()
:
的值 return
#include <iostream>
#include <boost/asio.hpp>
#include <functional>
using namespace std;
void SayHello()
{
std::cout<<"Hello!"<<std::endl;
}
template <typename T>
T GetSum(T a, T b)
{
std::cout<<"Adding " << a << " and " << b << std::endl;
return a+b;
}
int main(int argc, char *argv[])
{
boost::asio::io_service ioservice;
ioservice.post(&SayHello);
ioservice.post(std::bind(&GetSum<double>,1,2));
ioservice.run();
return 0;
}
为什么?因为我正在设计一个线程池,而且我正在考虑我的选项,使用户能够获得他的函数的 return 值,而不必用另一个函数手动包装他的函数,该函数将捕获return对他的价值。
我的解决方案:
int main(int argc, char *argv[])
{
boost::asio::io_service ioservice;
ioservice.post(&SayHello);
double sum;
ioservice.post([&sum]()
{
sum = GetSum(1,2);
});
ioservice.run();
std::cout<< sum <<std::endl; //is 3
return 0;
}
但我仍然希望有一些更简单的绑定或其他东西。
如果目标是拥有一个简单的单行绑定类函数,同时为您捕获 return 值,您可以像这样实现它:
#include <iostream>
#include <boost/asio.hpp>
#include <functional>
using namespace std;
void SayHello()
{
std::cout<<"Hello!"<<std::endl;
}
template <typename T>
T GetSum(T a, T b)
{
std::cout<<"Adding " << a << " and " << b << std::endl;
return a+b;
}
template<typename R, typename F, typename... Args>
auto bind_return_value(R& r, F&& f, Args&&... args)
{
return [&]()
{
r = f(std::forward<Args>(args)...);
};
}
int main(int argc, char *argv[])
{
boost::asio::io_service ioservice;
ioservice.post(&SayHello);
double sum;
ioservice.post(bind_return_value(sum, &GetSum<double>, 1, 2));
ioservice.run();
std::cout<< sum <<std::endl; //is 3
return 0;
}
我想出了一个解决方案,灵感来自于使用类似 std::future
的建议。所以我使用了 std::future
,并且代码有效。
我所做的只是继承自 io_service
,并创建一个新方法 post_with_future
,它具有 return 值的未来。我将不胜感激批评此解决方案以改进它。
#include <iostream>
#include <functional>
#include <type_traits>
#include <future>
#include <boost/asio.hpp>
class future_io_service : public boost::asio::io_service
{
public:
template <typename FuncType>
std::future<typename std::result_of<FuncType()>::type> post_with_future(FuncType&& func)
{
//keep in mind that std::result_of is std::invoke_result in C++17
typedef typename std::result_of<FuncType()>::type return_type;
typedef typename std::packaged_task<return_type()> task_type;
//since post requires that the functions in it are copy-constructible, we use a shared pointer for the packaged_task since it's only movable and non-copyable
std::shared_ptr<task_type> task = std::make_shared<task_type>(std::move(func));
std::future<return_type> returned_future = task->get_future();
this->post(std::bind(&task_type::operator(),task));
return returned_future;
}
};
void SayHello()
{
std::cout<<"Hello!"<<std::endl;
}
template <typename T>
T GetSum(T a, T b)
{
std::cout<<"Adding " << a << " and " << b << std::endl;
return a+b;
}
int main()
{
future_io_service ioservice;
ioservice.post(&SayHello);
auto sum = ioservice.post_with_future(std::bind(&GetSum<int>,1,2));
ioservice.run();
std::cout<<sum.get()<<std::endl; //result is 3
return 0;
}
这是您可以通过使用 asio::use_future
和 async_result
来实现的方法。请注意,我通过按值传递事物并使用硬编码参数求和来保持示例简单。
#include <iostream>
#include <thread>
#include <asio.hpp>
#include <asio/use_future.hpp>
int get_sum(int a, int b)
{
return a + b;
}
template <typename Func, typename CompletionFunction>
auto perform_asyncly(asio::io_service& ios, Func f, CompletionFunction cfun)
{
using handler_type = typename asio::handler_type
<CompletionFunction, void(asio::error_code, int)>::type;
handler_type handler{cfun};
asio::async_result<handler_type> result(handler);
ios.post([handler, f]() mutable {
handler(asio::error_code{}, f(2, 2));
});
return result.get();
}
int main() {
asio::io_service ios;
asio::io_service::work wrk{ios};
std::thread t{[&]{ ios.run(); }};
auto res = perform_asyncly(ios, get_sum, asio::use_future);
std::cout << res.get() << std::endl;
t.join();
return 0;
}
下面的解决方案是我打算在我自己的应用程序中使用的。三个特点:
Functions/lambdas 是 post_function_use_future() 的参数。要求:函数必须 return 不是 void 的值,并且它们的输入参数必须为零。请注意,SayHello() return 现在是一个整数。
可以使用任何 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
如何从 boost::asio::io_service
中获取 return 值?是否可以使用一些绑定或任何不涉及重写函数的简单构造?
以下是一个最小的例子。我正在尝试捕获 GetSum()
:
#include <iostream>
#include <boost/asio.hpp>
#include <functional>
using namespace std;
void SayHello()
{
std::cout<<"Hello!"<<std::endl;
}
template <typename T>
T GetSum(T a, T b)
{
std::cout<<"Adding " << a << " and " << b << std::endl;
return a+b;
}
int main(int argc, char *argv[])
{
boost::asio::io_service ioservice;
ioservice.post(&SayHello);
ioservice.post(std::bind(&GetSum<double>,1,2));
ioservice.run();
return 0;
}
为什么?因为我正在设计一个线程池,而且我正在考虑我的选项,使用户能够获得他的函数的 return 值,而不必用另一个函数手动包装他的函数,该函数将捕获return对他的价值。
我的解决方案:
int main(int argc, char *argv[])
{
boost::asio::io_service ioservice;
ioservice.post(&SayHello);
double sum;
ioservice.post([&sum]()
{
sum = GetSum(1,2);
});
ioservice.run();
std::cout<< sum <<std::endl; //is 3
return 0;
}
但我仍然希望有一些更简单的绑定或其他东西。
如果目标是拥有一个简单的单行绑定类函数,同时为您捕获 return 值,您可以像这样实现它:
#include <iostream>
#include <boost/asio.hpp>
#include <functional>
using namespace std;
void SayHello()
{
std::cout<<"Hello!"<<std::endl;
}
template <typename T>
T GetSum(T a, T b)
{
std::cout<<"Adding " << a << " and " << b << std::endl;
return a+b;
}
template<typename R, typename F, typename... Args>
auto bind_return_value(R& r, F&& f, Args&&... args)
{
return [&]()
{
r = f(std::forward<Args>(args)...);
};
}
int main(int argc, char *argv[])
{
boost::asio::io_service ioservice;
ioservice.post(&SayHello);
double sum;
ioservice.post(bind_return_value(sum, &GetSum<double>, 1, 2));
ioservice.run();
std::cout<< sum <<std::endl; //is 3
return 0;
}
我想出了一个解决方案,灵感来自于使用类似 std::future
的建议。所以我使用了 std::future
,并且代码有效。
我所做的只是继承自 io_service
,并创建一个新方法 post_with_future
,它具有 return 值的未来。我将不胜感激批评此解决方案以改进它。
#include <iostream>
#include <functional>
#include <type_traits>
#include <future>
#include <boost/asio.hpp>
class future_io_service : public boost::asio::io_service
{
public:
template <typename FuncType>
std::future<typename std::result_of<FuncType()>::type> post_with_future(FuncType&& func)
{
//keep in mind that std::result_of is std::invoke_result in C++17
typedef typename std::result_of<FuncType()>::type return_type;
typedef typename std::packaged_task<return_type()> task_type;
//since post requires that the functions in it are copy-constructible, we use a shared pointer for the packaged_task since it's only movable and non-copyable
std::shared_ptr<task_type> task = std::make_shared<task_type>(std::move(func));
std::future<return_type> returned_future = task->get_future();
this->post(std::bind(&task_type::operator(),task));
return returned_future;
}
};
void SayHello()
{
std::cout<<"Hello!"<<std::endl;
}
template <typename T>
T GetSum(T a, T b)
{
std::cout<<"Adding " << a << " and " << b << std::endl;
return a+b;
}
int main()
{
future_io_service ioservice;
ioservice.post(&SayHello);
auto sum = ioservice.post_with_future(std::bind(&GetSum<int>,1,2));
ioservice.run();
std::cout<<sum.get()<<std::endl; //result is 3
return 0;
}
这是您可以通过使用 asio::use_future
和 async_result
来实现的方法。请注意,我通过按值传递事物并使用硬编码参数求和来保持示例简单。
#include <iostream>
#include <thread>
#include <asio.hpp>
#include <asio/use_future.hpp>
int get_sum(int a, int b)
{
return a + b;
}
template <typename Func, typename CompletionFunction>
auto perform_asyncly(asio::io_service& ios, Func f, CompletionFunction cfun)
{
using handler_type = typename asio::handler_type
<CompletionFunction, void(asio::error_code, int)>::type;
handler_type handler{cfun};
asio::async_result<handler_type> result(handler);
ios.post([handler, f]() mutable {
handler(asio::error_code{}, f(2, 2));
});
return result.get();
}
int main() {
asio::io_service ios;
asio::io_service::work wrk{ios};
std::thread t{[&]{ ios.run(); }};
auto res = perform_asyncly(ios, get_sum, asio::use_future);
std::cout << res.get() << std::endl;
t.join();
return 0;
}
下面的解决方案是我打算在我自己的应用程序中使用的。三个特点:
Functions/lambdas 是 post_function_use_future() 的参数。要求:函数必须 return 不是 void 的值,并且它们的输入参数必须为零。请注意,SayHello() return 现在是一个整数。
可以使用任何 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