c++classc++11templatesdynamictype

C++ choose template type of class member in constructor


I'm trying to define template class inside of nontemplate class, below you may see the code of what i'm actually trying to do (it doesn't compilable for obvious reason). The main question is how can I realize that using C++11 (preferable) or C++14?

  1. Actually I've got solution using std::variant or same function from the BOOST library, but I need to know another way to solve that.

  2. I found old similar question, and answer by Anne Quinn sounds valuable (he suggest to declare subclasses for each type I need), but how to apply that in code right?

Code:

#include <vector>
#include <cstdint>

enum Type {
    INT16,
    UINT32
};

template<typename T>
class Buffer {
public:
    Buffer(uint32_t paramSize) {
        buffer.resize(paramSize);
    }

private:
    std::vector<T> buffer;
};

class Foo {
public:
    Foo(Type paramType, uint32_t paramSize) {
        switch(paramType) {
        case UINT32:
            buffer = Buffer<uint32_t>(paramSize);
            break;
        case INT16:
            buffer = Buffer<int16_t>(paramSize);
            break;
        }
    }

private:
    Buffer buffer;
};

int main() {
    Foo var(INT16, 30);

    return 0;
}

UPD1: answer by @user2308211 seems work, but I got two problems with that. In case I'm copying object Foo and original object destroys for some reason (moving out of scope for example), copy will stay with pointer to nowhere. Second one is how to retrieve my buffer through Foo class.

UPD2: shared_ptr resolves problem with copying, but then copy will store the same object, in case you wanna modify them independently, use copy constructor as shown in answer. As for access to original buffer, void pointer allow you to retrieve pointer to vector, then you should static_cast it to your type.

Thanks!


Solution

  • Have a base class with all the required functions for Buffer as pure virtual.

    #include <vector>
    #include <cstdint>
    
    enum Type {
        INT16,
        UINT32
    };
    
    class BufferBase {
    public:
        virtual void someFn()=0;
        virtual ~BufferBase() {}
    };
    
    template<typename T>
    class Buffer:public BufferBase {
    public:
        Buffer(uint32_t paramSize) {
            buffer.resize(paramSize);
        }
    
        void someFn() override {
          //functionality.
        }
        ~Buffer() {}
    
    private:
        std::vector<T> buffer;
    };
    
    class Foo {
    public:
        Foo(Type paramType, uint32_t paramSize) {
            this->bufferType = paramType;
            switch(paramType) {
            case UINT32:
                buffer = new Buffer<uint32_t>(paramSize);
                break;
            case INT16:
                buffer = new Buffer<int16_t>(paramSize);
                break;
            }
        }
        ~Foo() {
            delete this->buffer;
        }
        Foo &operator=(const Foo &other) {
            this->bufferType = other.bufferType;
            switch(bufferType) {
            case UINT32:
                buffer = new Buffer<uint32_t>(*static_cast<Buffer<uint32_t>*>(other.buffer));
                break;
            case INT16:
                buffer = new Buffer<int16_t>(*static_cast<Buffer<int16_t>*>(other.buffer));
                break;
            }
            return *this;
        }
        Foo(const Foo &other) {
            *this=other;
        }
    
    private:
        BufferBase *buffer;
        Type bufferType;
    };
    
    int main() {
        Foo var1(INT16, 30), var2(UINT32, 25);
        var1 = var2;
    
        return 0;
    }
    

    EDIT: I've updated the answer with a copy constructor.