It's possible with C++11 and decltype
. For that, we'll exploit that a pointer-to-member is not a pointer into the derived class when the member is inherited from a base class.
For example:
struct base{
void f(){}
};
struct derived : base{};
The type of &derived::f
will be void (base::*)()
, not void (derived::*)()
. This was already true in C++03, but it was impossible to get the base class type without actually specifying it. With decltype
, it's easy and only needs this little function:
// unimplemented to make sure it's only used
// in unevaluated contexts (sizeof, decltype, alignof)
template<class T, class U>
T base_of(U T::*);
Usage:
#include <iostream>
// unimplemented to make sure it's only used
// in unevaluated contexts (sizeof, decltype, alignof)
template<class T, class R>
T base_of(R T::*);
struct base{
void f(){}
void name(){ std::cout << "base::name()
"; }
};
struct derived : base{
void name(){ std::cout << "derived::name()
"; }
};
struct not_deducible : base{
void f(){}
void name(){ std::cout << "not_deducible::name()
"; }
};
int main(){
decltype(base_of(&derived::f)) a;
decltype(base_of(&base::f)) b;
decltype(base_of(¬_deducible::f)) c;
a.name();
b.name();
c.name();
}
Output:
base::name()
base::name()
not_deducible::name()
As the last example shows, you need to use a member that is actually an inherited member of the base class you're interested in.
There are more flaws, however: The member must also be unambiguously identify a base class member:
struct base2{ void f(){} };
struct not_deducible2 : base, base2{};
int main(){
decltype(base_of(¬_deducible2::f)) x; // error: 'f' is ambiguous
}
That's the best you can get though, without compiler support.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…