diff --git a/CHANGELOG.md b/CHANGELOG.md index ee13516f..fe6a2688 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ Version 84: * Tidy up buffer_front * static_buffer::consume improvement * multi_buffer is type-check friendly +* bind_handler allows placeholders -------------------------------------------------------------------------------- diff --git a/include/beast/core/bind_handler.hpp b/include/beast/core/bind_handler.hpp index a4a30280..b884c980 100644 --- a/include/beast/core/bind_handler.hpp +++ b/include/beast/core/bind_handler.hpp @@ -18,11 +18,14 @@ namespace beast { /** Bind parameters to a completion handler, creating a new handler. - This function creates a new handler which, when invoked with no - parameters, calls the original handler with the list of bound - arguments. The passed handler and arguments are forwarded into - the returned handler, which provides the same `io_service` - execution guarantees as the original handler. + This function creates a new handler which, when invoked, calls + the original handler with the list of bound arguments. Any + parameters passed in the invocation will be subtituted for + placeholders present in the list of bound arguments. Parameters + which are not matched to placeholders are silently discarded. + The passed handler and arguments are forwarded into the returned + handler, which provides the same `io_service` execution guarantees + as the original handler. Unlike `boost::asio::io_service::wrap`, the returned handler can be used in a subsequent call to `boost::asio::io_service::post` @@ -57,9 +60,11 @@ detail::bound_handler< #endif bind_handler(Handler&& handler, Args&&... args) { +#if 0 static_assert(is_completion_handler< Handler, void(Args...)>::value, "Handler requirements not met"); +#endif return detail::bound_handler::type, Args...>(std::forward< Handler>(handler), std::forward(args)...); diff --git a/include/beast/core/detail/bind_handler.hpp b/include/beast/core/detail/bind_handler.hpp index ad9f4e48..3afa47eb 100644 --- a/include/beast/core/detail/bind_handler.hpp +++ b/include/beast/core/detail/bind_handler.hpp @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include namespace beast { @@ -32,16 +34,72 @@ private: Handler h_; args_type args_; - template - static void invoke(Handler& h, Tuple& args, + template + static + typename std::enable_if< + std::is_placeholder::type>::value == 0, + Arg&&>::type + extract(Arg&& arg, Vals& vals) + { + return arg; + } + + template + static + typename std::enable_if< + std::is_placeholder::type>::value != 0, + typename std::tuple_element< + std::is_placeholder< + typename std::decay::type>::value - 1, + Vals>::type&&>::type + extract(Arg&&, Vals&& vals) + { + return std::get::type>::value - 1>( + std::forward(vals)); + } + + template< + class ArgsTuple, + std::size_t... S> + static + void + invoke( + Handler& h, + ArgsTuple& args, + std::tuple<>&&, index_sequence) { + boost::ignore_unused(args); h(std::get(args)...); } + template< + class ArgsTuple, + class ValsTuple, + std::size_t... S> + static + void + invoke( + Handler& h, + ArgsTuple& args, + ValsTuple&& vals, + index_sequence) + { + boost::ignore_unused(args); + boost::ignore_unused(vals); + h(extract(std::get(args), + std::forward(vals))...); + } + public: using result_type = void; + bound_handler(bound_handler&&) = default; + bound_handler(bound_handler const&) = default; + template explicit bound_handler( @@ -51,17 +109,23 @@ public: { } + template void - operator()() + operator()(Values&&... values) { invoke(h_, args_, + std::forward_as_tuple( + std::forward(values)...), index_sequence_for()); } + template void - operator()() const + operator()(Values&&... values) const { invoke(h_, args_, + std::forward_as_tuple( + std::forward(values)...), index_sequence_for()); } @@ -107,8 +171,6 @@ public: } // detail } // beast -#include - namespace std { template void diff --git a/test/core/bind_handler.cpp b/test/core/bind_handler.cpp index 85486325..05e9ac0c 100644 --- a/test/core/bind_handler.cpp +++ b/test/core/bind_handler.cpp @@ -10,17 +10,20 @@ #include #include -#include +#include namespace beast { class bind_handler_test : public unit_test::suite { public: + template struct handler { void - operator()() const; + operator()(Args const&...) const + { + } }; #if 0 @@ -28,7 +31,7 @@ public: void failStdBind() { - std::bind(bind_handler(handler{})); + std::bind(bind_handler(handler<>{})); } #endif @@ -37,14 +40,27 @@ public: { BEAST_EXPECT(v == 42); } + + void + testPlaceholders() + { + namespace ph = std::placeholders; + + bind_handler(handler<>{})(); + bind_handler(handler{}, 1)(); + bind_handler(handler{}, 1, "hello")(); + bind_handler(handler{}, ph::_1)(1); + bind_handler(handler{}, ph::_1, ph::_2)(1, "hello"); + } - void run() + void + run() override { auto f = bind_handler(std::bind( &bind_handler_test::callback, this, std::placeholders::_1), 42); f(); - pass(); + testPlaceholders(); } };