Как обрабатывать разные типы данных с помощью одного контейнера?

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

Мне нужно динамически создавать и заполнять по крайней мере несколько десятков векторов этих структур (каждый вектор содержит один тип структуры). Наиболее разумным способом доступа (идентификации) этих векторов является их тип данных.

Ниже мой нынешний подход. У меня нет доступа к C ++ 17.

Мой вопрос: я могу покрыть все управление памятью здесь? Создать какие-либо ненужные копии, которых можно избежать?

#include "stdafx.h"
#include <iostream>
#include <memory>
#include <vector>
#include <unordered_map>
#include <typeinfo>

// from a third party API

struct A {
    int a;
};

struct B {
    int a;
};

// ----

#define mapHash map[typeid(T).hash_code()]
typedef std::unordered_map<size_t, std::shared_ptr<void>> omniMap;

template <class T>
void addVect(omniMap &map) {
    if(mapHash == nullptr) {
        mapHash = std::make_shared<std::vector<T>>();
    }
    T s{};
    (*std::static_pointer_cast<std::vector<T>>(mapHash)).push_back(std::move(s));
}

template <class T>
std::shared_ptr<std::vector<T>> getVect(omniMap &map) {
    return std::static_pointer_cast<std::vector<T>>(mapHash);
}

template <class T>
void addElem(omniMap &map, const T &var) {
    mapHash = std::make_shared<T>(var);
}

template <class T>
std::shared_ptr<T> getElem(omniMap &map) {
    return std::static_pointer_cast<T>(mapHash);
}

int main()
{
    omniMap om;

    addVect<A>(om);
    addVect<A>(om);
    addVect<B>(om);

    addElem(om, 5);
    addElem(om, 2.5);
    addElem<std::string>(om, "hello");

    *getElem<int>(om) = 3;

    *getElem<double>(om) = 3.7;

    (*getVect<A>(om))[1].a = 15;

    std::cout << 
        (*getVect<A>(om))[1].a << "  " << 
        *getElem<int>(om) << "  " << 
        *getElem<double>(om) << "  " << 
        (*getElem<std::string>(om)).c_str() << std::endl;

    return 0;
}

output
15  3  3.7  hello

Всего 1 ответ


Вы не обязательно конвертируете информацию времени компиляции в структуры данных времени выполнения. Вам не нужно. Рассмотрим что-то вроде этого:

namespace internal {
  template <typename T>
  struct VectorHolder {
    static std::vector<T> vect;
  };
  template <typename T> std::vector<T> VectorHolder<T>::vect;
}

template <typename T>
std::vector<T>& getVect() { return internal::VectorHolder<T>::vect; }

template <class T>
void addVect() {
  getVect<T>().emplace_back();
}

// Other functions left as an exercise for the reader

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


Есть идеи?

10000