С++ выбирает тип шаблона члена класса в конструкторе

Я пытаюсь определить класс шаблона внутри класса, не являющегося шаблоном, ниже вы можете увидеть код того, что я на самом деле пытаюсь сделать (он не компилируется по очевидной причине). Главный вопрос заключается в том, как я могу реализовать это с помощью С++ 11 (предпочтительнее) или С++ 14?

  1. На самом деле у меня есть решение, использующее std::variant или ту же функцию из BOOST, но мне нужно знать другой способ решить эту проблему.

  2. Я нашел старый похожий вопрос и ответил Энн Куинн звучит ценно (он предлагает объявить подклассы для каждого типа, который мне нужен), но как правильно применить это в коде?

Код:

#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: ответ @user2308211 кажется рабочим, но у меня есть две проблемы с этим. В случае, если я копирую объект Foo, а исходный объект по какой-то причине уничтожается (например, выходит за пределы области видимости), копия останется с указателем в никуда. Во-вторых, как получить мой буфер через класс Foo.

UPD2: shared_ptr решает проблему с копированием, но тогда копия будет хранить тот же объект, если вы хотите изменить их независимо, используйте конструктор копирования, как показано в ответе. Что касается доступа к исходному буферу, указатель void позволяет вам получить указатель на вектор, тогда вы должны static_cast его привести к вашему типу.

Спасибо!


person Liastre    schedule 01.06.2017    source источник
comment
Вы можете сделать свой Buffer полиморфным и наследовать его от одной базы, не являющейся шаблоном.   -  person HolyBlackCat    schedule 02.06.2017
comment
@HolyBlackCat Мне нужно увидеть пример реализации, звучит для меня в новинку   -  person Liastre    schedule 02.06.2017


Ответы (1)


Иметь базовый класс со всеми необходимыми функциями для Buffer как чистого виртуального.

#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;
}

РЕДАКТИРОВАТЬ: я обновил ответ с помощью конструктора копирования.

person SPMP    schedule 02.06.2017
comment
Спасибо за ответ. Здесь только одна проблема, если я скопирую объект Foo и удалю оригинал, копия получит указатель в никуда. - person Liastre; 02.06.2017
comment
Вам нужно обновить конструктор копирования для Foo, чтобы выполнить глубокое копирование. Это даст вам правильное поведение. Если вы хотите оптимизировать дальше, вы можете подумать о создании конструктора перемещения, который будет переназначать указатели. - person SPMP; 02.06.2017
comment
Использование общего указателя оправдано только в том случае, если вы абсолютно уверены в том, что делаете. Насколько я понимаю, вы можете копировать объекты Foo и изменять их независимо. Общий указатель не даст вам этого. - person SPMP; 02.06.2017
comment
Ну да, это именно то, что я хочу, чтобы буфер действовал, он должен быть потокобезопасным и доступным через копии, так что в основном это должен быть один и тот же объект. Последняя проблема заключается в том, что я не могу получить данные буфера из класса Foo, я могу сделать это только через общедоступный указатель. - person Liastre; 02.06.2017