roschach
roschach

Reputation: 9376

Add different instantiations of a template class in the same container and call a template class method

Suppose I have these classes:

class A
{
   // virtual methods
};

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

I would like to add a subset of B classes into a container and from there, call ANewMethodSpecificOfClassB.

For example, given:

B<instanciation1> south_park;
B<instanciatoin2> family_guy;

suppose I want to put B<instanciation1> and B<instanciation2> in the same container (for example a vector): I cannot declare a std::vector<B> because B is not a real class, only B<instanciation1> and B<instanciation2> are.

Then I thought to define a vector using a (shared) pointer to the base class. However, doing so gives error when calling ANewMethodSpecificOfClassB because the method is not defined in the base class (and no, I can't modify the base class adding the method there).

Is there a way create a container with two different instances of a template classes and call a method that all of the instantiated classes have but not the parent class of the template class?

Upvotes: 0

Views: 123

Answers (1)

lorro
lorro

Reputation: 10880

There are (at least) two ways around this:

  1. You might define an intermediate class, AWithSpecificMethod:
class AWithSpecificMethod {
protected:
    virtual ANewMethodSpecificOfClassB() const = 0;
};

Then have B<> descend either from A or from AWithSpecificMethod. You can do that using std::conditional<>, std::is_same<> et. al.

However, this way of solving it, at some point, creates several interfaces and immediate classes which are not true abstractions, just a notation of existence of method. Also, it's virtual => likely very slow.

  1. You might store them in an std::variant<B<T1>, B<T2>, ...> and reconsider even if A is necessary as an interface class. This works if you know the possible types T1, T2, ... that you intend to work with (practically almost always). You can visit a variant using std::visit, which you usually pass a lambda and the variant:
std::variant<B<int>, B<char>> var;
std::visit([&](auto const& actual) {
    // here actual is the concrete type
    // either B<int> const& or B<char>&
}, var);

Upvotes: 2

Related Questions