std::function in C ++ 11 and 14 does not have the desired behavior.
It also prevents SFINAE from detecting bad overloads.
We can wrap it with another type that has the desired behavior ( void throwing back) and has poor SFINAE overload detection while we are on it as follows:
template<class Sig> struct checked_function; template<class R, class... Args> struct checked_function<R(Args...)>:std::function<R(Args...)> { using function = std::function<R(Args...)>; checked_function(std::nullptr_t):function() {} checked_function():function() {} template<class F, class=typename std::enable_if< std::is_convertible< typename std::result_of< F(Args...) >::type , R >::value >::type> checked_function( F&& f ):function( std::forward<F>(f) ) {} template<class F, class=typename std::enable_if< std::is_convertible< typename std::result_of< F(Args...) >::type , R >::value >::type> checked_function& operator=( F&& f ) { return function::operator=( std::forward<F>(f) ); } checked_function& operator=( checked_function const& o ) = default; checked_function& operator=( checked_function && o ) = default; checked_function( checked_function const& o ) = default; checked_function( checked_function && o ) = default; }; template<class... Args> struct checked_function<void(Args...)>:std::function<void(Args...)> { using function = std::function<void(Args...)>; checked_function(std::nullptr_t):function() {} checked_function():function() {} template<class F, class=typename std::enable_if< std::is_same< typename std::result_of< F(Args...) >::type , void >::value >::type> checked_function( F&& f, int*unused=nullptr ):function( std::forward<F>(f) ) {} template<class F> static auto wrap(F&& f){ return [f_=std::forward<F>(f)](auto&&...args){ f_( std::forward<decltype(args)>(args)... ); }; } template<class F, class=typename std::enable_if< !std::is_same< typename std::result_of< F(Args...) >::type , void >::value >::type> checked_function( F&& f, void*unused=nullptr ): function( wrap(std::forward<F>(f)) ) {} template<class F> typename std::enable_if< !std::is_same< typename std::result_of< F(Args...) >::type , void >::value, checked_function& >::type operator=( F&& f ) { return function::operator=( wrap(std::forward<F>(f)) ); } template<class F> typename std::enable_if< std::is_same< typename std::result_of< F(Args...) >::type , void >::value, checked_function& >::type operator=( F&& f ) { return function::operator=( std::forward<F>(f) ); } checked_function& operator=( checked_function const& o ) = default; checked_function& operator=( checked_function && o ) = default; checked_function( checked_function const& o ) = default; checked_function( checked_function && o ) = default; };
Now it compiles in C ++ 14 (not in C ++ 11, due to wrap : wrap can be replaced at the dial-peer with a copy of its own body, therefore ...). Perhaps it is possible to reduce the pattern using a beam.
It uses some features of C ++ 14 (in particular, in wrap ), you can do this by adding more templates).
Not yet launched.
source share