std::function
in C++11 and 14 does not have the behavior you desire.
It also fails to SFINAE detect bad overloads.
We can wrap it in a different type that both has the behavior you desire (void
discarding return) and has SFINAE bad overload detection while we are at it as follows:
template
struct checked_function;
template
struct checked_function:std::function {
using function = std::function;
checked_function(std::nullptr_t):function() {}
checked_function():function() {}
template::type
, R
>::value
>::type>
checked_function( F&& f ):function( std::forward(f) ) {}
template::type
, R
>::value
>::type>
checked_function& operator=( F&& f ) { return function::operator=( std::forward(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
struct checked_function:std::function {
using function = std::function;
checked_function(std::nullptr_t):function() {}
checked_function():function() {}
template::type
, void
>::value
>::type>
checked_function( F&& f, int*unused=nullptr ):function( std::forward(f) ) {}
template
static auto wrap(F&& f){
return [f_=std::forward(f)](auto&&...args){
f_( std::forward(args)... );
};
}
template::type
, void
>::value
>::type>
checked_function( F&& f, void*unused=nullptr ):
function( wrap(std::forward(f)) ) {}
template
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)) ); }
template
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) ); }
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;
};
It now compiles in C++14 (not in C++11, due to wrap
: wrap
can be replaced at point of call with a copy of its own body, so...). Could probably reduce boilerplate by a bunch.
It uses some C++14 features (move-into-lambda to be precise in wrap
-- you can do away with that by adding more boilerplate).
Not run yet.