How to create pointer to different instantiation of template class

  abstract-factory, c++, pointers

In making my first experiments with Abstract Factory in C++(while reading Modern C++ Design – A. Alexandrescu – part 9) i have a question.
If classes hierarchy looks like this:

struct B {}; 

struct D1 :public B {};
struct DD1 : public D1 {};
struct DD2 : public D1 {};

struct D2 :public B {};
struct DD3 : public D2 {};
struct DD4 : public D2 {};

I have this abstract factory code:


//abstract factory version 1

struct AbstractFactoryImpl
{
    virtual D1* CreateD1() = 0;
    virtual D2* CreateD2() = 0;
};

struct AbstractFactory : public AbstractFactoryImpl
{
    virtual D1* CreateD1() { return new D1; };
    virtual D2* CreateD2() { return new D2; };
};

template<class ... Ts>
struct ConcreteFactory :public AbstractFactory
{
    using params = std::tuple<Ts...>;
    using T1 = typename std::tuple_element_t<0, params>;
    using T2 = typename std::tuple_element_t<1, params>;

    virtual D1* CreateD1()override
    {
        static_assert(std::is_base_of_v<D1, T1>);
        return new T1;
    };
    virtual D2* CreateD2()override
    {
        static_assert(std::is_base_of_v<D2, T2>);
        return new T2;
    };
};

And using it in client code like this.

//version 1
    AbstractFactory* pFactory;
    pFactory = new ConcreteFactory<DD1, DD3>;
    D1* pD1 = pFactory->CreateD1();
    D2* pD2 = pFactory->CreateD2();

    pFactory = new ConcreteFactory<DD2, DD4>;
    pD1 = pFactory->CreateD1();
    pD2 = pFactory->CreateD2();

It works what i want and looks like a big part of examples in internet.

But in this version of abstract factorys if i want to add more classes in heirarchy(D3,DD5,DD6…) i must create too much code manually so i want to make code more generic.

//abstract factory version 2
template<typename T>
struct AbstractFactoryImpl_
{
    virtual T* Create() = 0;
};

template<typename T>
struct AbstractFactory_ :public AbstractFactoryImpl_<T>
{
    virtual T* Create() override
    {
        return new T;
    }
};

template<class ...Ts>
struct ConcreteFactory_ : public AbstractFactory_<Ts>...
{
    using params = std::tuple<Ts...>;
    using T1 = typename std::tuple_element_t<0, params>;
    using T2 = typename std::tuple_element_t<1, params>;

    template<class T>
    T* Create()
    {
        if constexpr (std::is_base_of_v<T, T1>)return AbstractFactory_<T1>::Create();
        else if constexpr (std::is_base_of_v<T, T2>)return AbstractFactory_<T2>::Create();

    }
};

And it works in client code like this:

        //version 2
    //AbstractFactory* pFactory; -- can`t use because AbstractFactory in version 2 is template class.
    auto pFactory_1 = new ConcreteFactory_<DD1, DD3>;
    D1* pD1_ = pFactory_1->Create<D1>();
    D2* pD2_ = pFactory_1->Create<D2>();

    auto pFactory_2 = new ConcreteFactory_<DD2, DD4>;
    pD1_ = pFactory_2->Create<D1>();
    pD2_ = pFactory_2->Create<D2>();

So it works but i must create two different pointers(pFactory_1,pFactory_2) to different instances of ConcreteFactory_. This is what not expected from Abstract Factory.
In first version it was ok because of virtual enheritance to call Create on Base class pointer. But here i have template base class. So i cant call on it pointer Create().
So the question is how to make pointer or something else may be std::any o std::variant to make it possible in this Abstract Factory class design? The client code i wanna make to work is same like first version.

    TYPE* pFactory_ = new ConcreteFactory_<DD1, DD3>;
    D1* pD1_ = pFactory_->Create<D1>();
    D2* pD2_ = pFactory_->Create<D2>();

    auto pFactory_ = new ConcreteFactory_<DD2, DD4>;
    pD1_ = pFactory_->Create<D1>();
    pD2_ = pFactory_->Create<D2>();

Full code:
[https://cppinsights.io/s/552bbe01]

Source: Windows Questions C++

LEAVE A COMMENT