0

See the code snip for the question:

class Base; 
typedef Base* BasePtr; 

template<typename D>
BasePtr CreateDerivedClass() {
    return new D();
}

class D1 : public Base {
....
};

class D2 : public Base {
....
}

void main() {
    std::string derived_name = {"D1", "D2"}; 
    std::vector<BasePtr> derived_vec; 
    for (auto& name : derived_name) {
// QUESTION: Other than factory design pattern, how can I pass the derived 
// class typename which is the value of string "name" to CreateDerivedClass<name> ?
        derived_vec.push_back(CreateDerivedClass<name>()); 
    }
}

Note: Here, I don't want to use the factory design pattern which required the derived class register itself during definition.

5
  • There are many methods to create a variable from a string value. See strtoul, std::istringstream. Since you didn't specify the type of variable, see also std::string::substr. Commented Sep 10, 2020 at 17:14
  • 1
    Although you don't have to register during definition, you still have to register at some point. Commented Sep 10, 2020 at 17:19
  • I agree with @Remy, a map holding the factory functions keyed by the stringized class names seems to be the best way. This map can be maintained in one place. Though self registration of the classes sounds even better, because you just have to consider that when implementing another derived class. I always have to manage it in a single file. Commented Sep 10, 2020 at 17:22
  • ^^^^ Note: Doesn't work with templates. Commented Sep 10, 2020 at 17:43
  • Thank you all for the answers. Thank you @drescherjm, what I am trying to figure out is if I can do this without registering the class. Now I got it that it is not possible. Thanks! Commented Sep 11, 2020 at 19:56

2 Answers 2

3

Template parameter values must be known at compile-time. There is simple no way to directly convert a string at runtime to a type for use in a template parameter. You will have to compare the string value at runtime to decide which CreateDerivedClass specialization to call.

For instance, the simplest way to handle this is to use a std::map where its elements hold pointers to the specialized functions that you want to be able to call, eg:

using createFuncType = BasePtr (*)();
std::map<std::string, createFuncType> createFuncs;
createFuncs["D1"] = &CreateDerivedClass<D1>;
createFuncs["D2"] = &CreateDerivedClass<D2>;
...

Then you can do this:

std::string derived_names[] = {"D1", "D2"}; 
std::vector<BasePtr> derived_vec; 
for (auto& name : derived_names) {
    derived_vec.push_back(createFuncs[name]());
}

There is really no other option in this situation.


That being said, you should be using std::unique_ptr<Base> instead of raw Base* pointers, eg:

#include <map>
#include <vector>
#include <string>
#include <memory>

class Base {
public:
    virtual ~Base() = default;
};

using BasePtr = std::unique_ptr<Base>;
using createFuncType = BasePtr (*)();

template<typename D>
BasePtr CreateDerivedClass() {
    return std::make_unique<D>();
}

class D1 : public Base {
    ...
};

class D2 : public Base {
    ...
}

...

int main() {
    std::map<std::string, createFuncType> createFuncs;
    createFuncs["D1"] = &CreateDerivedClass<D1>;
    createFuncs["D2"] = &CreateDerivedClass<D2>;
    ...

    std::string derived_names = {"D1", "D2", ...};
    std::vector<BasePtr> derived_vec; 
    for (auto& name : derived_names) {
        derived_vec.push_back(createFuncs[name]()); 
    }

    ...

    return 0;
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for answering the question. Yes, I used the factory design pattern and applied a map holding the factory function. What I am trying to figure out is if it is possible to do that without registering the class. Now it is clear that it is not possible, I have to register the class somewhere.
0

The type T of the template should be known in compilation time, this is because the compiler needs to create the piece of code matching to the implementation of the class/function with the type T. This is how templates in C++ work. What if derived_names will consist the value "D8" which is not a known type, we are going to have a trouble.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.