I'm trying to implement a mechanism to detect whether provided class contains some static method or not. It's quite simple code but I cannot understand why decltype()
doesn't work as expected for specialization of EnableIfHasFooMethod
class:
#include <iostream>
struct A {
static int Foo() { return 0; }
};
template <class T, class = void>
struct EnableIfHasFooMethod {};
template <class T>
struct EnableIfHasFooMethod<T, decltype(T::Foo)> {
typedef void type;
};
template <class T, class = void>
struct HasFooMethod {
static const bool value = false;
};
template <class T>
struct HasFooMethod<T, typename EnableIfHasFooMethod<T>::type> {
static const bool value = true;
};
int main() {
std::cout << HasFooMethod<A>::value << std::endl;
return 0;
}
Output is 0
, but should be 1
.
You forget to add void()
template <class T>
struct EnableIfHasFooMethod<T, decltype(T::Foo, void())> { /* ... */ };
// ...........................................^^^^^^^^
You need to match the second type (void
) in
// ........................vvvv
template <class T, class = void>
struct EnableIfHasFooMethod {};
so your decltype()
must return void
iff (if and only if) there is a Foo()
member in T
.
You can't write
decltype( T::Foo )
because, in this case, decltype()
return the type of the member Foo
(if present) that can't be void
.
You can't write
decltype( void() )
because, in this case, decltype()
return ever void
, but you want it iff there is a Foo
member in T
So the solution is
decltype( T::Foo , void() )
so SFINAE can work, failing the substitution, if there isn't a Foo
member and returning void
if there is Foo
.