Christian Panov
Christian Panov

Reputation: 85

C++ - Pushing variadic template class object into vector

class Base
{
public:
    virtual void foo() = 0;
};

class A : public Base
{
public:
    void foo() override { std::cout << "A\n"; }
};

class B : public Base
{
public:
    void foo() override { std::cout << "B\n"; }
};

class Registry
{
public:
    static Registry& instance()
    {
        static Registry s_instance;
        return s_instance;
    }

    void register_foo(Base* foo) 
    { 
        m_vec.emplace_back(foo); 
    }

private:
    std::vector<Base*> m_vec;
};

template<typename ... T>
class Foo : public T...
{
public:
    Foo()
    { 
        Registry::instance().register_foo(this);
    }

    void test() { (T::foo(), ...); }
};

int main()
{
    auto f1 = std::make_unique<Foo<A, B>>();
    auto f2 = std::make_unique<Foo<A>>();

    f1->test();
    f2->test();
}

As you can see I have a Base class, class A and class B.

A and B inherit from Base. Class Foo is a template class, which is with a variadic template. The idea is to be able to pass class A and class B into Foo. Then this Foo is registered in the Registry class / pushed into a vector.

The problem is the following - as you can see I can have both Foo<A> and Foo<A, B>, or Foo<B, A>. How can I have such a vector which can accept all possible types of Foo?

Upvotes: 0

Views: 280

Answers (2)

user4442671
user4442671

Reputation:

How about a simple common base class?

class FooBase {
public:
    virtual ~FooBase() {}

    virtual void test() = 0;
};

template<typename... T>
class Foo : public FooBase, public T...
{
public:
    Foo() { }

    void test() override { (T::foo(), ...); }
};

int main()
{
    auto f1 = std::make_unique<Foo<A, B>>();
    auto f2 = std::make_unique<Foo<A>>();

    std::vector<std::unique_ptr<FooBase>> foos;

    foos.push_back(std::move(f1));
    foos.push_back(std::move(f2));
}

Upvotes: 1

Jesper Juhl
Jesper Juhl

Reputation: 31457

A std::vector holds one type of objects. You cannot put objects of different types into the same vector (and objects created from a template with different template arguments are different types).

One option (I'd not recommend it) is having a vector that holds instances of std::any) - works, but cumbersome and inefficient to work with. Another option is a vector of pointers to a common base class and taking advantage of polymorphism. A third option is simply having sepperate vectors for each type of object.

Upvotes: 0

Related Questions