Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to instanciate base template classes explicitly?

This question is considering explicit instanciation of template classes.

Consider a template class B<T> derived from another template class A<T>. I want to explicitly instanicate B<T> because its methods are to be called from dynamic linking, so the methods must be instanciated although they are not called in the code itself. Of course, also methods inherited from A<T> will be called, so they must be instanciated as well.

It seems that C++ does NOT instanciate base classes when explicitly instanciating a template class, as asked in this question: Do Explicit Instantiations of C++ Class Templates Instantiate Dependent Base Classes? Example:

template<typename T>
class A{ void foo(){...} };

template<typename T>
class B : public A<T> {}

template class B<int>; // This will NOT instanciate A<int>::foo()!!!

Of course, I also need to instanciate all base classes. However, I don't want to burden the client code with this because the class hierarchy may be very deep. Consider a class hierarchy involving 10 or more template classes. The client should not be urged to write 10 explicit template instanciations. This is not only a lot of writing; it will also break when I introduce changes to the class hierarchy.

Instead, I want to achieve somehow that whenever B<T> is instanciated, then so are all its base classes. I tried simply instanciating the base class in B itself like this:

template<typename T>
class B : public A<T> {
    template class A<T>; // Does not compile!
}

But this does not compile. Are there other ways that could achive this?

like image 548
gexicide Avatar asked May 19 '14 13:05

gexicide


1 Answers

Maybe not elegant but at least workable: provide a macro to instantiate the template and require the user to use the macro in stead of manual instantiation:

// in A.hpp
#define INSTANTIATE_A(T) template class A<T>;

// in B.hpp
#define INSTANTIATE_B(T) \
    INSTANTIATE_A(T)     \
    template class B<T>;

And if you prefer "polluting" the class interface to enforcing the use of an instantiation macro: add a protected member that calls all other member functions of the template and the version in the base class. Example:

template<typename T>
class A
{
    void foo() {...}
protected:
    void instantiate() { foo(); }
};

template<typename T>
class B : public A<T>
{
    void bar() {...}
protected:
    void instantiate() { A<T>::instantiate(); bar(); }
};

template class B<int>; // Now works as expected

Update:

Alternative to the second solution: take the function pointer of all members and save them to a temporary variable:

template<typename T>
class A
{
    void foo() {...}
protected:
    void instantiate() { void (A::*p)() = &A::foo; }
};

template<typename T>
class B : public A<T>
{
    void bar() {...}
protected:
    void instantiate() { A<T>::instantiate(); void (B::*p)() = &B::foo; }
};
like image 113
Olaf Mandel Avatar answered Sep 22 '22 01:09

Olaf Mandel