我正在尝试使用模板元编程来确定基类。有没有办法自动获取基类而不明确专门化每个派生类?
class foo { public: char * Name() { return "foo"; }; };
class bar : public foo { public: char * Name() { return "bar"; }; };
template< typename T > struct ClassInfo { typedef T Base; };
template<> struct ClassInfo<bar> { typedef foo Base; };
int main()
{
ClassInfo<foo>::Base A;
ClassInfo<bar>::Base B;
std::cout << A.Name(); //foo
std::cout << B.Name(); //foo
}
目前任何自动方法都需要选择第一个声明的基数,并且对于私人基地会失败。
答案 0 :(得分:17)
可以使用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
}
在没有编译器支持的情况下,这是最好的。
答案 1 :(得分:5)
我不知道任何基类选择模板,我不确定是否存在或者甚至是个好主意。有许多方法可以破坏可扩展性并违背继承精神。当bar
公开继承foo
时,bar
是 foo
用于所有实际目的,客户端代码不需要区分基类和衍生类。
基类中的公共typedef经常会划伤您可能需要划伤并且更清晰的痒:
class foo { public: typedef foo name_making_type; ... };
int main() {
Foo::name_making_type a;
Bar::name_making_type b;
}
答案 2 :(得分:5)
我的解决方案不是真的自动,但我能想到的最好。
Intrusive C ++ 03解决方案:
class B {};
class A : public B
{
public:
typedef B Base;
};
非侵入式C ++ 03解决方案:
class B {};
class A : public B {};
template<class T>
struct TypeInfo;
template<>
struct TypeInfo<A>
{
typedef B Base;
};
答案 3 :(得分:2)
基类有什么用?你是.NET或Java程序员吗?
C ++支持多重继承,也没有全局公共基类。因此,C ++类型可能包含零个,一个或多个基类。因此禁止使用定冠词。
由于 基类没有意义,所以无法找到它。
答案 4 :(得分:1)
使用C ++ 11,当您的类只从一个父级继承时,您可以创建一个侵入式方法来始终拥有base_t
成员:
template<class base_type>
struct labeled_base : public base_type
{
using base_t = base_type; // The original parent type
using base::base; // Inherit constructors
protected:
using base = labeled_base; // The real parent type
};
struct A { virtual void f() {} };
struct my_class : labeled_base<A>
{
my_class() : parent_t(required_params) {}
void f() override
{
// do_something_prefix();
base_t::f();
// do_something_postfix();
}
};
使用该类,您将始终拥有parent_t
别名,以调用父构造函数,就好像它是具有(可能)较短名称的base
构造函数,以及base_t
别名,使您的类不知道基类类型名称,如果它很长或模糊不清。
parent_t
别名受到保护,不会将其公开给公众。如果您不希望base_t
别名是公开的,则可以始终将labeled_base
作为protected
或private
继承,无需更改labeled_base
类定义
该基础应该具有0运行时或空间开销,因为它的方法是内联的,什么都不做,并且没有自己的属性。
答案 5 :(得分:0)
我正在为类似问题寻找便携式解决方案数月。但我还没有找到它。
G ++有__bases
和__direct_bases
。您可以将它们包装在类型列表中,然后访问其中的任何一个元素,例如带有std::tuple
的{{1}}。有关用法,请参阅libstdc++'s <tr2/type_traits>
。