Fix bind_handler, bind_front_handler:

This tidies up small corner cases and bugs with
the bind_handler and bind_front_handler wrappers:

* Legacy allocation hooks are deleted
* Fixes for bind_front_handler specializations
* Decay bound arguments first, to reduce template instantiations
* Proper moving and forwarding of bound arguments and call parameters
This commit is contained in:
Vinnie Falco
2018-12-11 13:35:14 -08:00
parent 120d5481e2
commit 2afe929bb7
3 changed files with 110 additions and 170 deletions

View File

@@ -8,6 +8,7 @@ Version 198:
* Add buffer_traits.hpp, buffers_type * Add buffer_traits.hpp, buffers_type
* Tidy up experimental files * Tidy up experimental files
* Tidy up core files * Tidy up core files
* Fix bind_handler, bind_front_handler
API Changes: API Changes:

View File

@@ -108,12 +108,16 @@ __implementation_defined__
#else #else
auto auto
#endif #endif
bind_front_handler(Handler&& handler, Args&&... args) -> bind_front_handler(
detail::bind_front_wrapper<typename Handler&& handler,
std::decay<Handler>::type, Args...> Args&&... args) ->
detail::bind_front_wrapper<
typename std::decay<Handler>::type,
typename std::decay<Args>::type...>
{ {
return detail::bind_front_wrapper<typename return detail::bind_front_wrapper<
std::decay<Handler>::type, Args...>( typename std::decay<Handler>::type,
typename std::decay<Args>::type...>(
std::forward<Handler>(handler), std::forward<Handler>(handler),
std::forward<Args>(args)...); std::forward<Args>(args)...);
} }

View File

@@ -37,8 +37,6 @@ class bind_wrapper
Handler h_; Handler h_;
args_type args_; args_type args_;
// Can't friend partial specializations,
// so we just friend the whole thing.
template<class T, class Executor> template<class T, class Executor>
friend struct net::associated_executor; friend struct net::associated_executor;
@@ -178,24 +176,6 @@ public:
asio_handler_invoke(f, std::addressof(w->h_)); asio_handler_invoke(f, std::addressof(w->h_));
} }
friend
void* asio_handler_allocate(
std::size_t size, bind_wrapper* op)
{
using net::asio_handler_allocate;
return asio_handler_allocate(
size, std::addressof(op->h_));
}
friend
void asio_handler_deallocate(
void* p, std::size_t size, bind_wrapper* op)
{
using net::asio_handler_deallocate;
asio_handler_deallocate(
p, size, std::addressof(op->h_));
}
friend friend
bool asio_handler_is_continuation( bool asio_handler_is_continuation(
bind_wrapper* op) bind_wrapper* op)
@@ -206,19 +186,17 @@ public:
} }
}; };
//------------------------------------------------------------------------------
template<class Handler, class... Args> template<class Handler, class... Args>
class bind_front_wrapper; class bind_front_wrapper;
//------------------------------------------------------------------------------
// 0-arg specialization // 0-arg specialization
template<class Handler> template<class Handler>
class bind_front_wrapper<Handler> class bind_front_wrapper<Handler>
{ {
Handler h_; Handler h_;
// Can't friend partial specializations,
// so we just friend the whole thing.
template<class T, class Executor> template<class T, class Executor>
friend struct net::associated_executor; friend struct net::associated_executor;
@@ -228,10 +206,10 @@ public:
bind_front_wrapper(bind_front_wrapper&&) = default; bind_front_wrapper(bind_front_wrapper&&) = default;
bind_front_wrapper(bind_front_wrapper const&) = default; bind_front_wrapper(bind_front_wrapper const&) = default;
template<class DeducedHandler> template<class Handler_>
explicit explicit
bind_front_wrapper(DeducedHandler&& handler) bind_front_wrapper(Handler_&& handler)
: h_(std::forward<DeducedHandler>(handler)) : h_(std::forward<Handler_>(handler))
{ {
} }
@@ -261,24 +239,6 @@ public:
asio_handler_invoke(f, std::addressof(w->h_)); asio_handler_invoke(f, std::addressof(w->h_));
} }
friend
void* asio_handler_allocate(
std::size_t size, bind_front_wrapper* op)
{
using net::asio_handler_allocate;
return asio_handler_allocate(
size, std::addressof(op->h_));
}
friend
void asio_handler_deallocate(
void* p, std::size_t size, bind_front_wrapper* op)
{
using net::asio_handler_deallocate;
asio_handler_deallocate(
p, size, std::addressof(op->h_));
}
friend friend
bool asio_handler_is_continuation( bool asio_handler_is_continuation(
bind_front_wrapper* op) bind_front_wrapper* op)
@@ -289,15 +249,15 @@ public:
} }
}; };
//------------------------------------------------------------------------------
// 1-arg specialization // 1-arg specialization
template<class Handler, class Arg> template<class Handler, class Arg>
class bind_front_wrapper<Handler, Arg> class bind_front_wrapper<Handler, Arg>
{ {
Handler h_; Handler h_;
typename std::decay<Arg>::type arg_; Arg arg_;
// Can't friend partial specializations,
// so we just friend the whole thing.
template<class T, class Executor> template<class T, class Executor>
friend struct net::associated_executor; friend struct net::associated_executor;
@@ -307,18 +267,21 @@ public:
bind_front_wrapper(bind_front_wrapper&&) = default; bind_front_wrapper(bind_front_wrapper&&) = default;
bind_front_wrapper(bind_front_wrapper const&) = default; bind_front_wrapper(bind_front_wrapper const&) = default;
template<class DeducedHandler> template<
class Handler_,
class Arg_>
bind_front_wrapper( bind_front_wrapper(
DeducedHandler&& handler, Arg&& arg) Handler_&& handler,
: h_(std::forward<DeducedHandler>(handler)) Arg_&& arg)
, arg_(std::forward<Arg>(arg)) : h_(std::forward<Handler_>(handler))
, arg_(std::forward<Arg_>(arg))
{ {
} }
template<class... Ts> template<class... Ts>
void operator()(Ts&&... ts) void operator()(Ts&&... ts)
{ {
h_( std::forward<Arg>(arg_), h_( std::move(arg_),
std::forward<Ts>(ts)...); std::forward<Ts>(ts)...);
} }
@@ -342,24 +305,6 @@ public:
asio_handler_invoke(f, std::addressof(w->h_)); asio_handler_invoke(f, std::addressof(w->h_));
} }
friend
void* asio_handler_allocate(
std::size_t size, bind_front_wrapper* op)
{
using net::asio_handler_allocate;
return asio_handler_allocate(
size, std::addressof(op->h_));
}
friend
void asio_handler_deallocate(
void* p, std::size_t size, bind_front_wrapper* op)
{
using net::asio_handler_deallocate;
asio_handler_deallocate(
p, size, std::addressof(op->h_));
}
friend friend
bool asio_handler_is_continuation( bool asio_handler_is_continuation(
bind_front_wrapper* op) bind_front_wrapper* op)
@@ -370,16 +315,16 @@ public:
} }
}; };
//------------------------------------------------------------------------------
// 2-arg specialization // 2-arg specialization
template<class Handler, class Arg1, class Arg2> template<class Handler, class Arg1, class Arg2>
class bind_front_wrapper<Handler, Arg1, Arg2> class bind_front_wrapper<Handler, Arg1, Arg2>
{ {
Handler h_; Handler h_;
typename std::decay<Arg1>::type arg1_; Arg1 arg1_;
typename std::decay<Arg2>::type arg2_; Arg2 arg2_;
// Can't friend partial specializations,
// so we just friend the whole thing.
template<class T, class Executor> template<class T, class Executor>
friend struct net::associated_executor; friend struct net::associated_executor;
@@ -389,20 +334,25 @@ public:
bind_front_wrapper(bind_front_wrapper&&) = default; bind_front_wrapper(bind_front_wrapper&&) = default;
bind_front_wrapper(bind_front_wrapper const&) = default; bind_front_wrapper(bind_front_wrapper const&) = default;
template<class DeducedHandler> template<
bind_front_wrapper(DeducedHandler&& handler, class Handler_,
Arg1&& arg1, Arg2&& arg2) class Arg1_,
: h_(std::forward<DeducedHandler>(handler)) class Arg2_>
, arg1_(std::forward<Arg1>(arg1)) bind_front_wrapper(
, arg2_(std::forward<Arg2>(arg2)) Handler_&& handler,
Arg1_&& arg1,
Arg2_&& arg2)
: h_(std::forward<Handler_>(handler))
, arg1_(std::forward<Arg1_>(arg1))
, arg2_(std::forward<Arg2_>(arg2))
{ {
} }
template<class... Ts> template<class... Ts>
void operator()(Ts&&... ts) void operator()(Ts&&... ts)
{ {
h_( std::forward<Arg1>(arg1_), h_( std::move(arg1_),
std::forward<Arg2>(arg2_), std::move(arg2_),
std::forward<Ts>(ts)...); std::forward<Ts>(ts)...);
} }
@@ -426,24 +376,6 @@ public:
asio_handler_invoke(f, std::addressof(w->h_)); asio_handler_invoke(f, std::addressof(w->h_));
} }
friend
void* asio_handler_allocate(
std::size_t size, bind_front_wrapper* op)
{
using net::asio_handler_allocate;
return asio_handler_allocate(
size, std::addressof(op->h_));
}
friend
void asio_handler_deallocate(
void* p, std::size_t size, bind_front_wrapper* op)
{
using net::asio_handler_deallocate;
asio_handler_deallocate(
p, size, std::addressof(op->h_));
}
friend friend
bool asio_handler_is_continuation( bool asio_handler_is_continuation(
bind_front_wrapper* op) bind_front_wrapper* op)
@@ -452,24 +384,23 @@ public:
return asio_handler_is_continuation( return asio_handler_is_continuation(
std::addressof(op->h_)); std::addressof(op->h_));
} }
}; };
//------------------------------------------------------------------------------
// 3+ arg specialization // 3+ arg specialization
template<class Handler, template<
class Arg1, class Arg2, class Arg3, class... Args> class Handler,
class bind_front_wrapper<Handler, Arg1, Arg2, Arg3, Args...> class Arg1, class Arg2, class Arg3,
class... Args>
class bind_front_wrapper<
Handler, Arg1, Arg2, Arg3, Args...>
{ {
using args_type = tuple<
typename std::decay<Arg1>::type,
typename std::decay<Arg2>::type,
typename std::decay<Arg3>::type,
typename std::decay<Args>::type...>;
Handler h_; Handler h_;
args_type args_; detail::tuple<
Arg1, Arg2, Arg3, Args...> args_;
// Can't friend partial specializations,
// so we just friend the whole thing.
template<class T, class Executor> template<class T, class Executor>
friend struct net::associated_executor; friend struct net::associated_executor;
@@ -489,16 +420,22 @@ public:
bind_front_wrapper(bind_front_wrapper&&) = default; bind_front_wrapper(bind_front_wrapper&&) = default;
bind_front_wrapper(bind_front_wrapper const&) = default; bind_front_wrapper(bind_front_wrapper const&) = default;
template<class DeducedHandler> template<
bind_front_wrapper(DeducedHandler&& handler, class Handler_,
Arg1&& arg1, Arg2&& arg2, Arg3&& arg3, class Arg1_, class Arg2_, class Arg3_,
Args&&... args) class... Args_>
: h_(std::forward<DeducedHandler>(handler)) bind_front_wrapper(
Handler_&& handler,
Arg1_&& arg1,
Arg2_&& arg2,
Arg3_&& arg3,
Args_&&... args)
: h_(std::forward<Handler_>(handler))
, args_( , args_(
std::forward<Arg1>(arg1), std::forward<Arg1_>(arg1),
std::forward<Arg2>(arg2), std::forward<Arg2_>(arg2),
std::forward<Arg3>(arg3), std::forward<Arg3_>(arg3),
std::forward<Args>(args)...) std::forward<Args_>(args)...)
{ {
} }
@@ -531,24 +468,6 @@ public:
asio_handler_invoke(f, std::addressof(w->h_)); asio_handler_invoke(f, std::addressof(w->h_));
} }
friend
void* asio_handler_allocate(
std::size_t size, bind_front_wrapper* op)
{
using net::asio_handler_allocate;
return asio_handler_allocate(
size, std::addressof(op->h_));
}
friend
void asio_handler_deallocate(
void* p, std::size_t size, bind_front_wrapper* op)
{
using net::asio_handler_deallocate;
asio_handler_deallocate(
p, size, std::addressof(op->h_));
}
friend friend
bool asio_handler_is_continuation( bool asio_handler_is_continuation(
bind_front_wrapper* op) bind_front_wrapper* op)
@@ -567,6 +486,9 @@ template<class Handler>
class bind_front_wrapper< class bind_front_wrapper<
Handler, error_code, std::size_t> Handler, error_code, std::size_t>
{ {
template<class T, class Executor>
friend struct net::associated_executor;
Handler h_; Handler h_;
error_code ec_; error_code ec_;
std::size_t n_; std::size_t n_;
@@ -586,9 +508,10 @@ public:
{ {
} }
void operator()() template<class... Ts>
void operator()(Ts&&... ts)
{ {
h_(ec_, n_); h_(ec_, n_, std::forward<Ts>(ts)...);
} }
// //
@@ -611,24 +534,6 @@ public:
asio_handler_invoke(f, std::addressof(w->h_)); asio_handler_invoke(f, std::addressof(w->h_));
} }
friend
void* asio_handler_allocate(
std::size_t size, bind_front_wrapper* op)
{
using net::asio_handler_allocate;
return asio_handler_allocate(
size, std::addressof(op->h_));
}
friend
void asio_handler_deallocate(
void* p, std::size_t size, bind_front_wrapper* op)
{
using net::asio_handler_deallocate;
asio_handler_deallocate(
p, size, std::addressof(op->h_));
}
friend friend
bool asio_handler_is_continuation( bool asio_handler_is_continuation(
bind_front_wrapper* op) bind_front_wrapper* op)
@@ -639,6 +544,29 @@ public:
} }
}; };
//------------------------------------------------------------------------------
// VFALCO These are only called when using deprecated
// network interfaces in conjunction with extensions,
// and should not be needed. If this creates a problem
// please contact me.
template<class Handler, class... Args>
void* asio_handler_allocate(std::size_t,
bind_wrapper<Handler, Args...>* op) = delete;
template<class Handler, class... Args>
void asio_handler_deallocate(void*, std::size_t,
bind_wrapper<Handler, Args...>* op) = delete;
template<class Handler, class... Args>
void* asio_handler_allocate(std::size_t,
bind_front_wrapper<Handler, Args...>* op) = delete;
template<class Handler, class... Args>
void asio_handler_deallocate(void*, std::size_t,
bind_front_wrapper<Handler, Args...>* op) = delete;
} // detail } // detail
} // beast } // beast
} // boost } // boost
@@ -689,6 +617,13 @@ struct associated_executor<
namespace std { namespace std {
// VFALCO Using std::bind on a completion handler will
// cause undefined behavior later, because the executor
// associated with the handler is not propagated to the
// wrapper returned by std::bind; these overloads are
// deleted to prevent mistakes. If this creates a problem
// please contact me.
template<class Handler, class... Args> template<class Handler, class... Args>
void void
bind(boost::beast::detail::bind_wrapper< bind(boost::beast::detail::bind_wrapper<