I found similar questions and answers like this one. However, as I tried out, this SFINAE tests only succeeded if the tested member is directly defined in the class being tested. For example the following, class B
, D1
print HAS
while the other two print NOT HAS
. Is there a way to determine that if a class has a member, whether it is defined by itself, or a base class, and the name of the base class is not known in this case. The motivation is that I want to write a generic function that will call a certain method if it exists (from base or not, the type of the parameter is generic, leave along the type of its possible base).
#include <iostream>
class HasFoo
{
public :
typedef char Small;
typedef struct {char; char;} Large;
template <typename C, void (C::*) ()> class SFINAE {};
template <typename C> static Small test (SFINAE<C, &C::foo> *)
{
std::cout << "HAS" << std::endl;
}
template <typename C> static Large test (...)
{
std::cout << "NOT HAS" << std::endl;
}
};
class B
{
public :
void foo () {}
};
class D1 : public B
{
public :
void foo () {} // overide
};
class D2 : public B
{
public :
using B::foo;
};
class D3 : public B {};
int main ()
{
HasFoo::test<B>(0);
HasFoo::test<D1>(0);
HasFoo::test<D2>(0);
HasFoo::test<D3>(0);
}
Unfortunately it wouldn't be possible at least in C++03 and I doubt in C++11 also.
Few important points:
public
private
andprotected
inheritance the SFINAE may end up uselesspublic
method/inheritance, the codeHasFoo::test<>
can be enhanced for taking multiple parameters where a base class also can be passed;std::is_base_of<>
can be used for further validation of the base/derived relationship; then apply the same logic for base class alsoThere is a way to determine if a class hierachy has a member of a given name. It uses SFINAE and introduces substituation failure in name lookup by creating an ambiguity. Additionally, there is a way to test if public members are callable; however, there is not a way to determine if a member is public with SFINAE.
Here is an example:
Which produces the following output:
has_foo
only checks for the existence of a member namedfoo
. It does not verify thatfoo
is a callable member (a public member function or public member that is a functor).can_call_foo
checks ifT::foo()
is callable. IfT::foo()
is not public, then a compiler error will occur. As far as I know, there is no way to prevent this via SFINAE. For a more complete and brilliant, but fairly complex solution, check here.In C++03, this is unfortunately not possible, sorry.
In C++11, things get much easier thanks to the magic of
decltype
.decltype
lets you write expressions to deduce the type of their result, so you can perfectly name a member of a base class. And if the method is template, then SFINAE applies to thedecltype
expression.Unfortunately ideone has a version of gcc that's too old for this and clang 3.0 is no better.