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