Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can the type of a base class be obtained from a template type automatically?

I am trying to use template meta-programming to determine the base class. Is there a way to get the base class automatically without explicitly specializing for each derived class?

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
}

for right now any automatic method would need to select the first declared base and would fail for private bases.

like image 356
Anephezeton Avatar asked Jan 03 '12 07:01

Anephezeton


People also ask

Can a template class inherit from a non template class?

Deriving from a non-template base classIt is quite possible to have a template class inherit from a 'normal' class. This mechanism is recommended if your template class has a lot of non-template attributes and operations. Instead of putting them in the template class, put them into a non-template base class.

Can we inherit template class?

Inherited Member Functions of Class Templates are not Available.

How is a template class different from a template function?

For normal code, you would use a class template when you want to create a class that is parameterised by a type, and a function template when you want to create a function that can operate on many different types.

Does template allow us to define generic classes and functions?

Templates are the foundation of generic programming, which involves writing code in a way that is independent of any particular type. A template is a blueprint or formula for creating a generic class or a function.


2 Answers

I am looking for a portable resolution for similar problems for months. But I don't find it yet.

G++ has __bases and __direct_bases. You can wrap them in a type list and then access any one of its elements, e.g. a std::tuple with std::tuple_element. See libstdc++'s <tr2/type_traits> for usage.

However, this is not portable. Clang++ currently has no such intrinsics.

like image 101
FrankHB Avatar answered Nov 09 '22 23:11

FrankHB


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()\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();
}

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(&not_deducible2::f)) x; // error: 'f' is ambiguous
}

That's the best you can get though, without compiler support.

like image 29
Xeo Avatar answered Nov 09 '22 22:11

Xeo