C++11 和 14 中的std::function 没有您想要的行为。
SFINAE 也无法检测到严重的过载。
我们可以将它包装成另一种类型,既具有您想要的行为(void 丢弃返回),又具有 SFINAE 错误过载检测,而我们如下:
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;
};
它现在在 C++14 中编译(不是在 C++11 中,因为 wrap:wrap 可以在调用点替换为它自己的主体副本,所以......)。可能会减少一堆样板。
它使用了一些 C++14 特性(确切地说是 wrap 中的 move-into-lambda -- 你可以通过添加更多样板来消除它)。
尚未运行。