Как создать массив объектов шаблонного класса?

Я не делал никакого программирования на C++ в течение довольно долгого времени, и я решил, что я буду возиться с ним немного в свободное время, поэтому я решил написать мне небольшую программу базы данных просто для удовольствия, и у меня возникли проблемы с созданием массива шаблонных объектов класса.

у меня есть этот класс, который я хочу использовать для представления поля в записи базы данных.

template <class T, int fieldTypeId>
class Field
{
private:
    T field;
    int field_type;
public:
    // ...
};

и я хочу использовать массив этого класса представляют собой запись в базе данных, используя этот класс.

class Database_Record
{
private:
    int id;
    Field record[];
public:
    Database_Record(int);
    Database_Record(int, Field[]);
   ~Database_Record();
};

где я застрял, это создание массива в Database_Record class так как это массив объектов templated class с каждым элементом, возможно, другого типа, и я не уверен, как мне нужно объявить массив из-за этого. Возможно ли то, что я пытаюсь сделать, или я делаю это неправильно? Любая помощь будет очень признательна.

7 ответов


Field<T1> и Field<T2> два совершенно разных видах. Для их лечения в векторе нужно generialize потом куда-то. Вы можете написать AbstractField и

struct AbstractField{
  virtual ~AbstractField() = 0;
};

template<class T,int fieldTypeId>
class Field: public AbstractField{
  private:
    T field;
  public:
    const static int field_type;
  public:
    virtual ~Field(){}
};

class Database_Record{
  std::vector<AbstractField*> record; 
  public:
    ~Database_Record(){
      //delete all AbstractFields in vector
    }
};

и затем сохранить vector of AbstractField. также используйте vector вместо []. Использовать AbstractField* вместо AbstractField и напишите хотя бы один чистый виртуальный в AbstractField.

вы можете сделать деструктор AbstractField чисто виртуальные. и не забудьте удалить все AbstractFields. в ~Database_Record()


вы идете не в ту сторону.

шаблоны используются для создания различных типа: std::vector<int> и std::vector<float> различны во многом так же (и столько же), как int и float есть.

ваш синтаксис также неверен; чтобы создать динамический массив, вы бы поместили следующий член в свой Database_Record:

 std::vector<Field> record; // if this was possible; however, it's not

чтобы поместить несколько объектов различного типа в один массив, они должны иметь общий базовый класс.


для того чтобы создать массив различных типов вам нужен базовый класс для объектов и массив будет массив указателей базового класса. Так, например,

class Field
{
public:
    virtual ~Field() {}
    virtual std::string toString() const = 0;
    // and possibly other interface functions...
};

template <class T> FieldImpl : public Field
{
public:
    virtual std::string toString() const
    {
        std::stringstream ss;
        ss << val;
        return ss.str();
    }

    // implementation of possibly other interface functions        

private:
    T val;
}

будут типы, которые вам нужны. Тогда массив будет чем-то вроде

std::vector<std::unique_ptr<Field>> my_array;

затем вы можете делать вещи с Ваш массив с помощью функции, интерфейс, Эл. г.

my_array[i]->toString();

считайте каждый экземпляр с другим аргументом шаблона другим классом. Вам либо нужно сохранить определенный класс (т. е. Field<int, 17>) или вам нужен Field иметь не шаблонный базовый класс, который can сохранить в списке.


вы можете сделать что-то вроде этого -

template <class T, int fieldTypeId>
class Field
{
private:
    T field;
    int field_Type;
};

template <class T, int fieldTypeId>
class Database_record
{
private:
    int id;
    std::vector<Field<T, fieldTypeId> > record_;
};

Вы делаете шаблоны неправильно. Шаблоны инстанцировать класс с различные типы будут давать два разных типа снова с возможно разных размеров, что делает невозможным их хранение в массиве.

если вы хотите обрабатывать разные типы равномерно, используйте наследование. И при использовании наследования не используйте простые массивы, но vector или std::array.

в вашем коде также есть куча странных вещей: зачем хранить fieldTypeId когда его статически? Я думаю, это связано с тип T вы используете в качестве параметра шаблона. Externalise механизм через частичные специализации:

template<typename T>
struct fieldTypeId;

template<>
struct fieldTypeId<int> {
  const static int value = 0;
}; 
// etc....

если я совершенно не прав, и вы действительно знаете, что делаете: используйте тип стирания через any тип (например,импульс.Любой).


как уже было сказано ранее, шаблоны C++ не работает.

в то же время использование наследования и векторов указателей не подходит для реализации записей БД из-за ограничений производительности.

сделайте шаг назад и посмотрите на проблему более абстрактно. Как я понимаю из вашего кода, цель состоит в том, чтобы упаковать произвольное количество полей разных типов в непрерывный блок памяти. Схематично:

struct DBRecord {
    Type1 f1;
    Type2 f2;
    Type3 f3;
    Type4 f4;
    // etc...
}

вы можете достигните этого немного уродливой, но практической конструкцией, состоящей из абстрактного объявления шаблона и нескольких специализаций.

декларация будет выглядеть так:

template <
    typename T1,
    typename T2 = void,
    typename T3 = void,
    typename T4 = void,
    typename T5 = void,
    typename T6 = void,
    typename T7 = void,
    typename T8 = void,
    typename T9 = void,
    typename T10 = void
> struct DBRecord;

Это ограничивает максимальное количество полей для определенного числа очевидно. Если вам нужно действительно произвольное количество полей, вам нужно переключиться на ориентированную на столбец парадигму.

затем частичные специализации должны объявлять анатомию структур для каждого числа аргументов от 1 до 10:

template <
    typename T1
> struct DBRecord <T1, void, void, void, void, void, void, void, void, void> 
{
    int id;
    T1 f1;
    DBRecord(int ID, T1 F1) {/*...*/};
};

template <
    typename T1,
    typename T2
> struct DBRecord <T1, T2, void, void, void, void, void, void, void, void> 
{
    int id;
    T1 f1;
    T2 f2;
    DBRecord(int ID, T1 F1, T2 F2) {/*...*/};
};

// etc...

теперь вы можете выделить таблицы как массивы записей определенных типов в одном new[] звоните, если хотите. И вы обычно не заботитесь о разрушении каждого поля, так как вы освобождаете память обо всей структуре.

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