Get parent of type T in a template function

1.1k views Asked by At

I want to find out what is the parent of the type class T in a template function, suppose I've the following classes:

class A{
...
}

class B: public A{
...
}

class C: public B{
...
}


template<typename T>
size_t getBaseHashCode()
{
  return typeid(base_of(T)).hashcode();
}

int main()
{
  A a;
  C c;
  size_t size = getBaseHashCode<C>();// must return hashcode of class B
}

is there anyway to find parent of type T and implement base_of function?

Edit: indeed what I want to do is:

I've factory class which creates objects for me:

template <typename B>
class Factory{
public:
    template <typename D>
    void registerType(std::string name)
    {
        static_assert(std::is_base_of<B, D>::value, "class doesn't derive from the base");
        table_[name] = &createFunc<D>;
    }
    B* create(std::string name)
    {
        const auto it = table_.find(name);
        if(it != table_.end())
            return it->second();
        FILE_LOG(logERROR) << "unidentified option, acceptable options are:";
        for(auto const &m : list())
            FILE_LOG(logERROR) << '\t' << m;
        return nullptr;
    }

    std::vector<std::string> list()
    {
        std::vector<std::string> lst;
        for(auto const &iter : table_)
            lst.push_back(iter.first);
        return lst;
    }
private:
    template<typename D>
    static B* createFunc()
    {
        return new D();
    }
    typedef B* (*PCreateFunc)();
    std::map<std::string, PCreateFunc> table_;
};

in the registerType function I want to set some properties of type D or it's parent and then in the create function, I want to create objects based on that.

2

There are 2 answers

0
W.F. On

You might also consider using some parent wrappers to automatize typedefing:

#include <type_traits>
#include <typeinfo>
#include <iostream>

template <class P>
struct base: P {
    using base_type = P;
};

struct A{ };
struct B: base<A>{ };
struct C: base<B>{ };

template <class T>
auto base_of(T) -> typename T::base_type;

template <class T>
using base_of_t = decltype(base_of(std::declval<T>()));

int main() {
    std::cout << typeid(base_of_t<C>).name() << std::endl;
}

Output:

1B

Output of c++filt -t 1B:

B

[live demo]

Note it still does not deal with multiple inheritance

6
skypjack On

You can use a couple of functions declarations that you don't have to define.
It follows a minimal, working example:

#include<utility>
#include<typeinfo>
#include<iostream>

class A{};
class B: public A{};
class C: public B{};

B base_of(const C &);
A base_of(const B &);

template<typename T>
void getBaseHashCode() {
    std::cout << typeid(decltype(base_of(std::declval<T>()))).name() << std::endl;
}

int main() {
    getBaseHashCode<B>();
    getBaseHashCode<C>();
}

It exploits the fact that, in this case, you have exact matches during the invokations. It's quite weak a solution, but works with the example code in the question.


That said, I agree on the fact that the whole question looks like an XY-problem.

EDIT

As mentioned by @Jarod42 in the comments, a more idiomatic (and verbose) way would be by using traits.
It follows a minimal, working example:

#include<typeinfo>
#include<iostream>

class A{};
class B: public A{};
class C: public B{};

template<typename> struct base_of;
template<> struct base_of<B> { using type = A; };
template<> struct base_of<C> { using type = B; };

template<typename T>
void getBaseHashCode() {
    std::cout << typeid(typename base_of<T>::type).name() << std::endl;
}

int main() {
    getBaseHashCode<B>();
    getBaseHashCode<C>();
}

This will solve also the problem due to multiple inheritance. The designer of base_of specializations will be in charge to promote one of the base classes to the role of preferred one.