Home > Enterprise >  How to create a "factory function" for a templated class?
How to create a "factory function" for a templated class?

Time:04-13

How would someone go about implementing a factory function for a templated class? Either my google searches aren't looking for the right thing, or I am misunderstanding the results. As an example:

template<typename T>
class Test
{
public:
    T data;
    void SizeOfData() { std::cout << "Data Size:" << sizeof(data) << "\n"; }
};

----this what I am trying to figure out how to do------
template <typename T>
Test<T> FactoryFunction(const std::string& type)
{
     if(type == "int")
        return Test<int>;
     if(type == "long")
        return Test<long long>;
}
----------------------------------------
int main()
{
    auto a = FactoryFunction(std::string("int"));
    auto b = FactoryFunction(std::string("long"));
    a.SizeOfData();
    b.SizeOfData();
    a.data = 1;
    b.data = 2;
}

Obviously, this code is all wrong - I am just trying to show what I want to do in theory. Can it be done? What do I look up in google - Factory functions to return templated classes? I am not even sure where to start. If someone could even point me in a direction - I really just want a function the returns the correct template instantiation based on the results of a switch or if/else list. I think conceptually the idea isn't hard, but implementing it is another thing - or I am really missing something.

Thanks for any help.

CodePudding user response:

The type T of a templated function has to be determined in compile time. Therefore you cannot do it the way you mentioned.

However - you can use the following pattern to achieve a similar result:

#include <assert.h>

class TestBase
{
public:
    virtual void SizeOfData() = 0;
};

template<typename T>
class Test : public TestBase
{
public:
    T data;
    virtual void SizeOfData() override { std::cout << "Data Size:" << sizeof(data) << "\n"; }
};

std::unique_ptr<TestBase> FactoryFunction(const std::string& type)
{
    if (type == "int")
        return std::make_unique<Test<int>>();
    if (type == "long")
        return std::make_unique<Test<long long>>();
    return nullptr;
}

int main()
{
    auto a = FactoryFunction(std::string("int"));
    assert(a);
    auto b = FactoryFunction(std::string("long"));
    assert(b);
    a->SizeOfData();
    b->SizeOfData();
}

Some notes:

  1. Each instance of Test (where T changes) is a differnt an unrelated class. In order to create a connection between them, I added a common base class.

  2. In order to use polymorphism, you must use refernce semantics. Therefore the factory returns a pointer (in this case a std::unique_ptr).

  3. The common method you need to invoke on all your Test objects (SizeOfData) became a virtual method in the base class.

  4. This technique is actually related to the idiom of type erasure mentioned in the comments.

UPDATE: based on the comment below, I replaced using naked news with std::make_unique. You can see more info why it is better here: Differences between std::make_unique and std::unique_ptr with new

  • Related