Это возможно с C ++ 11 и decltype
.Для этого мы воспользуемся тем, что указатель на член не является указателем на производный класс, когда член наследуется от базового класса.
Например:
struct base{
void f(){}
};
struct derived : base{};
Тип &derived::f
будет void (base::*)()
, а не void (derived::*)()
.Это было уже верно в C ++ 03, но было невозможно получить тип базового класса без его фактического указания.С decltype
это просто и нуждается только в этой маленькой функции:
// unimplemented to make sure it's only used
// in unevaluated contexts (sizeof, decltype, alignof)
template<class T, class U>
T base_of(U T::*);
Использование:
#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()\n"; }
};
struct derived : base{
void name(){ std::cout << "derived::name()\n"; }
};
struct not_deducible : base{
void f(){}
void name(){ std::cout << "not_deducible::name()\n"; }
};
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();
}
Вывод:
base::name()
base::name()
not_deducible::name()
Как показывает последний пример, вам нужно использовать член, который на самом деле является унаследованным членом интересующего вас базового класса.
Однако есть и другие недостатки: член также должен однозначно идентифицировать члена базового класса:
struct base2{ void f(){} };
struct not_deducible2 : base, base2{};
int main(){
decltype(base_of(¬_deducible2::f)) x; // error: 'f' is ambiguous
}
Это лучшее, что вы можете получить без поддержки компилятора.