Как известно каждому разработчику C++, некоторые популярные контейнеры предоставляются в STL. А как насчет табличного контейнера? Пока я пишу эту статью, в Интернете трудно найти простого кандидата. Вы можете найти некоторые библиотеки, но большинство из них разработаны для более сложных задач, таких как подключение и представление таблиц баз данных. Но что, если нам нужна простая таблица, чтобы настроить ее под наши нужды. Например, что, если нам нужно, чтобы обновления в локальном экземпляре таблицы отправлялись в удаленные экземпляры на других машинах?

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

  • Схема таблицы известна до того, как мы создадим ее экземпляр. Поэтому нам не нужно менять тип столбца или добавлять новый столбец.
  • Один столбец, который используется в качестве индекса. Нет двух строк с одинаковым индексом.
  • Нет необходимости изменять столбец, который используется в качестве индекса после создания экземпляра таблицы.

При проектировании и разработке настольного контейнера необходимо учитывать некоторые моменты:

  • Поскольку каждая строка уникальна с учетом столбца индекса, можно использовать простую карту std::map из индекса в строки.
  • Элементы в каждой строке относятся к разным типам.
  • Первый вариант обработки таких разнородных данных — использование структуры или класса для представления строки. Но это возлагает ответственность за управление элементами строки на плечи клиента контейнера. Так что это вредит принципу инкапсуляции.
  • Другой возможный вариант — использовать std::vector элементов void* или некоторые лучшие альтернативы, такие как boost::any. Но использование void* не является хорошей привычкой, и его следует избегать, насколько это возможно. Кроме того, использование void* приводит к тому, что разработчик обрабатывает данные реального типа, что приводит к возникновению ошибок в коде.
  • Третий вариант представления строки — использование std::tuple. Поскольку std::tuple требует, чтобы типы каждого элемента были указаны аргументами шаблона, будет выполняться статическая проверка типов, в отличие от динамической проверки типов в std::vector элементов void*. Статическая проверка типов очень полезна, особенно в больших программах, чтобы избежать нежелательных ошибок во время компиляции.
  • Поскольку схема известна заранее, клиенту таблицы лучше указать ее в качестве аргументов шаблона. Предоставление типа каждого столбца в качестве аргумента шаблона позволяет иметь статическую проверку типов в реализации табличного контейнера.
  • Аргументы шаблона табличного контейнера можно использовать для указания аргументов шаблона std::tuple, используемых в качестве строк таблицы.
  • Но количество столбцов непостоянно. Поэтому мы должны использовать шаблон variadic в C++ для реализации класса Table.
  • Если нам нужно предоставить имена столбцов в качестве входных данных таких функций, как конструктор, нам нужно использовать шаблон с переменным числом аргументов в другой раз. Нам нужно проверить, что количество имен столбцов совпадает с аргументами шаблона для класса Table. Лучше знать ошибку во время компиляции. std::enable_if помогает нам достичь этой цели.

Контейнер таблицы с учетом пунктов этой статьи предоставлен на github.