I asked a question about a week ago inquiring how I would be able to simply instantiate a class template only if the type it took had a specific member function. In my answer I got sort of a complicated solution. But then I tried to do it on my own. I just wanted to know if this enough to figure out of a given type T
has a void function named f
taking 0 parameters.
#include <type_traits>
#include <utility>
template <typename T, typename = void>
struct has_f : std::false_type { };
template <typename T>
struct has_f<
T,
decltype(std::declval<T>().f(), void())> : std::true_type { };
template <typename T, typename = typename std::enable_if<has_f<T>::value>::type>
struct A { };
struct B
{
void f();
};
struct C { };
template class A<B>; // compiles
template class A<C>; // error: no type named ‘type’
// in ‘struct std::enable_if<false, void>’
If so, why are the other answers so complicated in this thread?
Substitution failure is not an error (SFINAE) refers to a situation in C++ where an invalid substitution of template parameters is not in itself an error. David Vandevoorde first introduced the acronym SFINAE to describe related programming techniques.
This rule applies during overload resolution of function templates: When substituting the explicitly specified or deduced type for the template parameter fails, the specialization is discarded from the overload set instead of causing a compile error. This feature is used in template metaprogramming.
" typename " is a keyword in the C++ programming language used when writing templates. It is used for specifying that a dependent name in a template definition or declaration is a type.
Yep, you have solved it in the simplest, most idiomatic style of C++11 SFINAE.
Note that you didn't check that the return type is void
, that it's a nonstatic member, nor that there are no parameters. f
is simply callable with no arguments. It could even be a functor.
To check for a nullary member nonstatic function returning void
, use
template <typename T>
struct has_f<T, decltype(void( static_cast< void (T::*)( void ) >( &T::f ) )) >
: std::true_type {};
template <typename T>
struct has_f<T, decltype(void( static_cast< void (T::*)( void ) const >( &T::f ) )) >
: std::true_type {};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With