C ++ - 智能指针向量的映射 - 全部继承自同一基类

时间:2016-05-08 11:55:50

标签: c++ c++11 dictionary vector stl

我的实体组件系统中有这个地图:

std::map<u_int32_t, std::vector<std::shared_ptr<Component>>> _componentMap;

u_int32_t是组件向量的关键。可以有同一组件的多个实例。 (这就是为什么有一个向量)。

现在我想要一个模板化的getter函数,它返回一个继承类型的Vector:

template<class T> inline const std::vector<std::shared_ptr<T>> & getVector() const
{
     u_int32_t key = getKey<T>();
     return static_cast<std::vector<std::shared_ptr<T>>>(_componentMap.count(key) ? _componentMap.at(key) : _emptyComponentVec);
}

我知道这不起作用,因为不同类型的std::vectors完全不相关,我不能在它们之间施放。我还希望每次调用此函数时都避免分配新的向量。

但我怎么能得到理想的行为呢?添加组件后,我可以创建所需派生类型的std::vector

问题还可能是:如何让std::map包含不同类型的std::vector

对于任何解决方案,我都无法与boost相关联,但如果绝对需要,我可以集成boost的单个标题。

3 个答案:

答案 0 :(得分:1)

这是我为此问题考虑的解决方案的粗略实现。当然,有很多房间可以改进代码,但希望它传达了我的想法。

#include <iostream>
#include <map>
#include <vector>
#include <memory>
using namespace std;

class Base {
public:
    virtual void f() const = 0;
};

class A : public Base {
public:
    static const int type = 0;
    explicit A(int a) : a_(a) {}
    void f() const { cout << "calling A::f" << endl;}
    int a_;
};
class B : public Base {
public:
    static const int type = 1;
    explicit B(int a) : a_(a) {}
    void f() const { cout << "calling B::f" << endl;}
    int a_;
};

class MapWrapper {
public:
    template<class T>
    void append(int a, vector<T> const& vec) {
        types_[a] = T::type;
        my_map_[a] = make_shared<vector<T>>(vec);
    }
    template<class T>
    vector<T> const& get(int a) const {
        return *static_pointer_cast<vector<T>>( my_map_.at(a) );
    }
    map<int, shared_ptr<void>> const& get_my_map() const {
        return my_map_;
    }
    vector<shared_ptr<Base>> get_base(int a) const {
        vector<shared_ptr<Base>> ret;
        switch(types_.at(a)) {
            case 0: {
                auto const vec = get<A>(a);
                for(auto v : vec)
                    ret.push_back(make_shared<A>(v));
                break;  
            }
            case 1: {
                auto const vec = get<B>(a);
                for(auto v : vec)
                    ret.push_back(make_shared<B>(v));
                break;  
            }
        }
        return ret;
    }
    map<int, shared_ptr<void>> my_map_;
    map<int, int> types_;
};  

int main() {
    MapWrapper map_wrapper;
    map_wrapper.append(10, vector<A>{A(2), A(4)});
    map_wrapper.append(20, vector<B>{B(5), B(7), B(9)});

    for(auto const& w : map_wrapper.get_my_map())
        for(auto v : map_wrapper.get_base(w.first))
            v->f();

    for(auto const& x: map_wrapper.get<A>(10))
        cout << x.a_ << " ";
    cout << endl;

    for(auto const& x: map_wrapper.get<B>(20))
        cout << x.a_ << " ";

    return 0;
}

答案 1 :(得分:1)

template<class It>
struct range_view {
  It b, e;
  It begin() const { return b; }
  It end() const { return e; }
  using reference = decltype(*std::declval<It const&>());
  reference operator[](std::size_t n) const
  {
    return b[n];
  }
  bool empty() const { return begin()==end(); }
  std::size_t size() const { return end()-begin(); }
  reference front() const {
    return *begin();
  }
  reference back() const {
    return *std::prev(end());
  }
  template<class O>
  range_view( O&& o ):
    b(std::begin(o)), e(std::end(o))
  {}
};

这是一个快速范围的视图。它可以改进。

现在您需要做的就是编写一个伪随机访问迭代器来转换它的参数。因此它需要在类型T上使用随机访问迭代器,然后执行一些操作F以返回类型U.它转发所有其他操作。

map然后存储std::vector<std::shared_ptr<Base>>。 gettor返回range_view< converting_iterator<spBase2spDerived> >

答案 2 :(得分:0)

解决方案是使用reinterpret_cast:

    while((value = getwords(oneword))!=1){  
        strcpy(all_words[num_words],oneword);
        // ....
    }
    strcpy(all_words[num_words],oneword); // Copy last word
    num_words++;

它不是很漂亮,但它确实可以正常工作,并且满足所有要求。