std::function
в С++ 11 и 14 не имеет желаемого поведения.
Также 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
можно заменить в точке вызова копией собственного тела, так что...). Вероятно, можно было бы уменьшить шаблон на кучу.
Он использует некоторые функции С++ 14 (точнее, перемещение в лямбда-выражение в wrap
- вы можете избавиться от этого, добавив больше шаблонов).
Еще не бегал.
person
Yakk - Adam Nevraumont
schedule
19.08.2014