I\'m asking for a template trick to detect if a class has a specific member function of a given signature.
The problem is similar to the one cited here http://www.go
Without C++11 support (decltype) this might work:
#include
using namespace std;
struct A { void foo(void); };
struct Aa: public A { };
struct B { };
struct retA { int foo(void); };
struct argA { void foo(double); };
struct constA { void foo(void) const; };
struct varA { int foo; };
template
struct FooFinder {
typedef char true_type[1];
typedef char false_type[2];
template
struct TypeSink;
template
static true_type &match(U);
template
static true_type &test(TypeSink( &U::foo ) )> *);
template
static false_type &test(...);
enum { value = (sizeof(test(0, 0)) == sizeof(true_type)) };
};
int main() {
cout << FooFinder::value << endl;
cout << FooFinder::value << endl;
cout << FooFinder::value << endl;
cout << FooFinder::value << endl;
cout << FooFinder::value << endl;
cout << FooFinder::value << endl;
cout << FooFinder::value << endl;
}
A, Aa and B are the clases in question, Aa being the special one that inherits the member we're looking for.
In the FooFinder the true_type and false_type are the replacements for the correspondent C++11 classes. Also for the understanding of template meta programming, they reveal the very basis of the SFINAE-sizeof-trick.
The TypeSink is a template struct that is used later to sink the integral result of the sizeof operator into a template instantiation to form a type.
The match function is another SFINAE kind of template that is left without a generic counterpart. It can hence only be instantiated if the type of its argument matches the type it was specialized for.
Both the test functions together with the enum declaration finally form the central SFINAE pattern. There is a generic one using an ellipsis that returns the false_type and a counterpart with more specific arguments to take precedence.
To be able to instantiate the test function with a template argument of T, the match function must be instantiated, as its return type is required to instantiate the TypeSink argument. The caveat is that &U::foo, being wrapped in a function argument, is not referred to from within a template argument specialization, so inherited member lookup still takes place.