2017-02-18 19 views
0

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

std::vector<std::vector<MyBaseClass>* > items; 

В идеале, я хотел бы предоставить API, где могут быть добавлены и доступны производные типы MyBaseClass (без специальных шаблонов). Что-то вроде этого:

T& addItem(size_t index, T& item); 
T& getItem(size_t index); 

Использование так:

AClass : public MyBaseClass {}; 
BClass : public MyBaseClass {}; 

addItem<AClass&>(123, item); 
addItem<BClass&>(456, item); 

AClass& = getItem<AClass&>(123); 
BClass& = getItem<BClass&>(456); 

Причина отсутствия специализированных шаблонов является то, что я хочу, чтобы разрешить использование новых производных типов без других разработчиков необходимости модифицировать этот код ,

Итак, есть ли способ, которым я могу реализовать этот API, не имея необходимости знать типы производных классов и специализировать код?

Можно ли это сделать с помощью союза и шаблона?

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

Примечание: Я использую C++ 11 без Boost.

Спасибо.

+4

'' std :: vector 'не может содержать объекты производных типов. Период. – aschepler

+4

Когда вы добавляете объекты к 'vector ', вектор будет хранить только часть базового класса объектов. См. [Что такое разбиение объектов?] (Http://stackoverflow.com/questions/274626/what-is-object-slicing) –

+0

Вы можете использовать 'std :: vector >', а затем просто добавьте 'addItem' действие на указатель и верните ссылку. Это, конечно, будет неопределенным поведением, если вы примените неверный тип и вернете недопустимую ссылку. – Cornstalks

ответ

0

Что-то вдоль этих линий возможно:

class FancyStore { 
public: 
    template <typename T> 
    T& addItem(const T& item) { 
    void*& raw = store_[typeid(T)]; 
    if (!raw) { 
     raw = new std::vector<T>(); 
    } 
    auto v = static_cast<std::vector<T>*>(raw); 
    v->push_back(item); 
    return v->back(); 
    }  

    template <typename T> 
    T& getItem(size_t index) { 
    void* raw = store_[typeid(T)]; 
    auto v = static_cast<std::vector<T>*>(raw); 
    return (*v)[index]; 
    } 

private: 
    std::unordered_map<std::type_index, void*> store_; 
}; 

Live demo. Копирование, деструктор, обработка ошибок остаются в качестве упражнения для читателя.

+0

Большое вам спасибо. Это похоже на то, что мне нужно. – user1824607

+0

Есть ли способ изменить размер всех векторов с помощью одного вызова функции, хотя я не знаю типы до времени выполнения? , например. void resizeItemStore (размер size_t); – user1824607

+0

Можно ли перебирать через store_ и использовать decltype для вызова шаблонизированной функции изменения размера? – user1824607