namespace details {
template<template<class...>class Z, class, class...Ts>
struct can_apply : std::false_type{};
template<template<class...>class Z, class...Ts>
struct can_apply<Z, std::void_t<Z<Ts...>>, Ts...> : std::true_type{};
}
template<template<class...>class Z, class...Ts>
using can_apply = details::can_apply<Z,void, Ts...>
template<class Sig>
using can_invoke = can_apply< std::result_of_t, Sig >;
We now have a traits class can_invoke
.
You pass it a signature. It is truthy if the signature is a valid call, and falsy otherwise.
template<class T>
std::enable_if_t< !can_invoke<T()> >
use_this( T obj ) {
obj->do_stuff();
}
template<class T>
std::enable_if_t< can_invoke<T()> >
use_this( T func ) {
use_this( func() );
}
I use some C++11, such as enable_if_t
, void_t
and result_of_t
. All are easy to write in C++11, and are easy to search for.
The behavior of result_of
when passed an invalid signature was changed in C++14. In C++11, it does not have to be SFINAE friendly. We can replace std::result_of_t
with invoke_result_r
in C++11 as follows:
template<class Sig, class=void>
struct invoke_result {};
template<class Sig>
using invoke_result = typename invoke_result<Sig>::type;
template<class F, class...Args>
struct invoke_result<F(Args...),
decltype( void( std::declval<F>()( std::declval<Args>()... ) ) )
> {
using type = decltype( std::declval<F>()( std::declval<Args>()... ) );
};
This is now SFINAE friendly.
can_apply
is similar to C++20's is_detected
, but shorter and to the point.
Note that doing this in a non-C++11 compiler, like MSVC, is impractical. You can do something similar with tag dispatching, however.