Станд. C++:: карта значений шаблонного класса

Я пытаюсь объявить a Row и a Column класс, с Row наличие частного std::map со значениями, указывающими на шаблонное Column. Что-то вроде этого:

template <typename T> class DataType {
  private:
    T type;
};
template <typename T> class Field {
  private:
    T value;
    DataType<T> type;
};
class Row {
  private:
    std::map<unsigned long,Field*> column;
}; 

Ну, я предполагаю в принципе Row классу не придется знать который отчасти Field (или Column) мы хотели бы использовать, т.е. является ли это a Field<int> в столбце 1 или a Field<double> в столбце 2. Но я не уверен, каков правильный синтаксис для Row::column объявление, или если std::map ограничен в этом смысле, и я должен использовать что-то еще.

Я appretiate Вы предложения и спасибо за них заранее.

13
задан jbatista 7 August 2019 в 18:15
поделиться

3 ответа

Field один не тип, а шаблон, который может генерировать семейство типов, такой как Field<int> и Field<double>. Все эти поля не связаны таким образом, что тот так или иначе получен из другой или такой. Таким образом, необходимо установить некоторое отношение между всеми этими сгенерированными типами. Один путь состоит в том, чтобы использовать общий нешаблонный базовый класс:

class FieldBase { };

template <typename T>
class Field : public FieldBase {
  private:
    T value;
    DataType<T> type;
};
class Row {
  private:
    std::map<unsigned long,FieldBase*> column;
}; 

И рассмотрите использование интеллектуального указателя вместо того необработанного указателя в коде. Так или иначе теперь проблема состоит в том, что информация типа потеряна - указываете ли Вы на a Field<double> или к a Field<int> больше не известен и может только быть обнаружен путем хранения своего рода флага типа в основе, которая установлена шаблонным производным классом - или путем выяснения у использования RTTI

dynamic_cast<Field<int>*>(field) != 0

Но это ужасно. Особенно, потому что, что Вы хотите, существует семантическое значение. Т.е. Вы хотели бы смочь скопировать свою строку, и она скопирует все поля в нем. И Вы хотели бы получить двойное, когда двойное хранится - без первого использования RTTI для взламывания пути к производному типу.

Один способ сделать его состоит в том, чтобы использовать дизъюнктное объединение. Это - в основном объединение для некоторых произвольных типов и кроме того флага типа, который хранит, какое значение в настоящее время хранится в том поле (например, ли двойное, международное...). Например:

template <typename T>
class Field {
  private:
    T value;
    DataType<T> type;
};
class Row {
  private:
    std::map<unsigned long, 
             boost::variant< Field<int>, Field<double> > > 
      column;
};

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

24
ответ дан 1 December 2019 в 21:38
поделиться
  1. Вы получили ошибку там: необходимо "оценить" участника в Поле (нужно, вероятно, быть "типом").
  2. Не сохраняйте необработанные указатели в значении карты. Используйте повышение:: shared_ptr.
  3. Кроме того, у Вас должно быть серьезное основание для записи таких классов, где уже существует много кода обработки DB/таблицы там, который можно, вероятно, использовать. Так, если это применимо, рассмотрите использование чего-то существующего и не пишущий Ваш собственный код обработки таблицы.

Теперь, для ответа на вопрос :), Поле <> классы могут наследоваться общему базовому классу, это совместно используется всеми типами данных. Таким образом, контейнер, такой как Ваша карта столбца может сохранить указатели (сделайте, это совместно использовало указатели) к производным объектам, которые инстанцируются шаблонного класса.

1
ответ дан 1 December 2019 в 21:38
поделиться

A Row< int, float, int> действительно отличается от a Row<int, std::string>. Очевидно, Row<int,float,int>.field<0> должен быть a Field<int> в то время как Row<int,float,int>.field<1> должен быть a Field<float>. И Row<int,float,int>.field<3> ошибка компилятора.

Самый легкий способ сделать так использует Повышение. Большая аналитика была введена впервые Loki (см. современный Дизайн C++ Andrei Alexandrescu), но Повышение более современно и лучше поддерживаемый.

Обычно, Вы не выполнили бы итерации по полям - каждое поле имеет свой собственный тип. Но Вас делают, Вам действительно был бы нужен a FieldBase. При необходимости в таком интерфейсе, вероятно, стоит также сохранить поля внутренне как a boost::array<FieldBase, N> (т.е. Row<int,float,int> имеет a boost::array<FieldBase, 3>). Вы никогда не должны должны быть dynamic_cast это FieldBase*,все же. Это - тест во время выполнения, и Вы всегда знаете точное T из каждого Field<T> во время компиляции.

0
ответ дан 1 December 2019 в 21:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: