Универсальная функция для заполнения вектора std::variant

Есть шаблонный класс,

template <size_t Num>
class some{
  int value[Num];
};

экземпляры которого мы будем хранить в векторе с помощью std::variant

std::vector<std::variant<some<3>, some<4>, some<8>>> v;

Теперь мне захотелось написать функцию, которая считывает данные из файла, которые записаны в следующем формате:

Кол-во элементов Элементы
3 1 2 3
4 32 1 30 98

Собственно вот и она:

 static void read(path p) {
   size_t num_elements;
   std::fstream input_file(p);
   ElementCreator<3> creator3;
   ElementCreator<4> creator4;
   ElementCreator<8> creator8;

   input_file >> num_elements;
   for (size_t ne = 0; ne < num_elements; ++ne) {
        input_file >> num_points_in_element;

        if (num_points_in_element == 3) {
          for (size_t np = 0; np < num_points_in_element; ++np) {
            input_file >> index;
            creator3.add_index(index);
          }

          v.emplace_back(creator3.get());
          creator3.clear();
        } else if (num_points_in_element == 4) {
          for (size_t np = 0; np < num_points_in_element; ++np) {
            input_file >> index;
            creator4.add_index(index);
          }

          v.emplace_back(creator4.get());
          creator4.clear();
        } else if (num_points_in_element == 8) {
          for (size_t np = 0; np < num_points_in_element; ++np) {
            input_file >> index;
            creator8.add_index(index);
          }

          v.emplace_back(creator8.get());
          creator8.clear();
        }
   }

Класс-создатель

template <size_t N>
struct ElementCreator {
  public:
    using element_type = some<N>;

  public:
    ~ElementCreator() = default;

  public:
    ElementCreator(const ElementCreator&)           = delete;
    ElementCreator(ElementCreator&&)                = delete;
    ElementCreator operator=(const ElementCreator&) = delete;
    ElementCreator operator=(ElementCreator&&)      = delete;

  public:
    ElementCreator()
      : _element(element_type{}){
    }

    void add_index(size_t index) {
      _element._value[_n] = index;
      ++_n;
    }


    const element_type& get() const {
      return _element;
    }

    void clear() {
      _element = element_type{};
    }

  private:
    element_type _element;
    size_t _n = 0;
};

Ой, как прекрасно! - подумал глупый программист.

Оказывается, что это работает только тогда, когда в векторе v и в функции read все типы совпадают. Если я захочу сделать вектор только из типов some<3> и some<4>, то это уже не скомпилируется, придётся убрать из функции часть кода для some<8>, то есть переписать её.

Глупый программист делает выводы:

  • Нельзя написать функцию с if-ами для каждого типа сразу (у меня их около 10)
  • Писать для каждого возможного варианта типов (перебором) это ∑(k = 1-10) n!/(k!(n-k)!) = 1 + 10 + 45 + 120 + 210 + 252 + 210 + 120 + 45 + 10 = очень много - я умру столько писать.

Давайте поможем ему не сделать еще одну ошибку и спасём мир от очередного самописного костыля.


Ответы (0 шт):