Can I add class template to tuple?

Viewed 102

I'm trying to add class template to tuple

These are my classes:

class Parent {
  // ...
}

class Child1 : public Parent {
  // ...
}

class Child2 : public Parent {
  // ...
}

My purpose is to add class like this way:

v.push_back({"child1", Child1});

so that I can save class template to create an object like this way:

Parent *obj = new v[0][1]();

which should work like this:

Parent *obj = new Child1();

I trid this:

std::vector<std::tuple<std::string, template<class T>>> v;

to add template to tuple.

How can I make it work?

1 Answers

No, you can't store a type directly. But you can store a function pointer, pointing to a function that constructs one of the derived classes when called.

std::vector<std::tuple<std::string, Parent *(*)()>> v;
v.push_back({"Child1", []() -> Parent * {return new Child1;}});

Parent *ptr = std::get<1>(v[0])();

Here, Parent *(*)() means "pointer to a function with no parameters, returning Parent *".

[]() -> Parent * {return new Child1;} is a lambda expression, which is more or less an anonymous function. () indicates no parameters, and -> Parent * indicates that the return type is Parent *.

Note std::get<1>(...) instead of ...[1]. The latter doesn't work on tuples. Note () at the end, which calls the function.

Since your tuple only has two elements, consider using a std::pair<...> instead. Then you could do v[0].second instead of std::get<1>(v[0]).

Since you seem to want to use the vector as a map from strings to functions, consider using an actual std::map instead of a vector.


Here's a full example using std::map:

#include <iostream>
#include <map>

class Parent
{
  public:
    virtual ~Parent() = default;
    virtual void foo() {std::cout << "Parent\n";}
};

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

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

int main()
{
    std::map<std::string, Parent *(*)()> m;
    m.insert({"Child1", []() -> Parent * {return new Child1;}});

    Parent *ptr = m.at("Child1")();
    ptr->foo(); // Prints `Child1`.
}
Related