可以自动从模板类型中获取基类的类型吗?

Ane*_*ton 9 c++ templates metaprogramming

我正在尝试使用模板元编程来确定基类.有没有办法自动获取基类而不明确专门为每个派生类?

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
}
Run Code Online (Sandbox Code Playgroud)

现在任何自动方法都需要选择第一个声明的基数,并且对于私人基地会失败.

Xeo*_*Xeo 17

它可以用C++ 11和decltype.为此,当成员从基类继承时,我们将利用指向成员的指针不是指向派生类的指针.

例如:

struct base{
    void f(){}
};
struct derived : base{};
Run Code Online (Sandbox Code Playgroud)

该类型的&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::*);
Run Code Online (Sandbox Code Playgroud)

用法:

#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(&not_deducible::f)) c;
    a.name();
    b.name();
    c.name();
}
Run Code Online (Sandbox Code Playgroud)

输出:

base::name()
base::name()
not_deducible::name()
Run Code Online (Sandbox Code Playgroud)

如最后一个示例所示,您需要使用一个实际上是您感兴趣的基类的继承成员的成员.

但是,还有更多缺陷:成员还必须明确地标识基类成员:

struct base2{ void f(){} };

struct not_deducible2 : base, base2{};

int main(){
  decltype(base_of(&not_deducible2::f)) x; // error: 'f' is ambiguous
}
Run Code Online (Sandbox Code Playgroud)

没有编译器支持,这是你可以获得的最好的.


thi*_*ton 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;
}
Run Code Online (Sandbox Code Playgroud)


Sta*_*ked 5

我的解决方案不是真的自动,但我能想到的最好.

侵入式C++ 03解决方案:

class B {};

class A : public B
{
public:
    typedef B Base;
};
Run Code Online (Sandbox Code Playgroud)

非侵入式C++ 03解决方案:

class B {};

class A : public B {};

template<class T>
struct TypeInfo;

template<>
struct TypeInfo<A>
{
    typedef B Base;
};
Run Code Online (Sandbox Code Playgroud)