我的实体组件系统中有这个地图:
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的单个标题。
答案 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++;
它不是很漂亮,但它确实可以正常工作,并且满足所有要求。