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);
}
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 the decltype expression.
#include <iostream>
template <typename T>
auto has_foo(T& t) -> decltype(t.foo(), bool()) { return true; }
bool has_foo(...) { return false; }
struct Base {
void foo() {}
};
struct Derived1: Base {
void foo() {}
};
struct Derived2: Base {
using Base::foo;
};
struct Derived3: Base {
};
int main() {
Base b; Derived1 d1; Derived2 d2; Derived3 d3;
std::cout << has_foo(b) << " "
<< has_foo(d1) << " "
<< has_foo(d2) << " "
<< has_foo(d3) << "\n";
}
Unfortunately ideone has a version of gcc that's too old for this and clang 3.0 is no better.
Unfortunately it wouldn't be possible at least in C++03 and I doubt in C++11 also.
Few important points:
public
private and protected inheritance the SFINAE
may end up uselesspublic method/inheritance,
the code HasFoo::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
alsoIf 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