向类添加额外的向量
Posted
技术标签:
【中文标题】向类添加额外的向量【英文标题】:Adding additional vectors to a class 【发布时间】:2014-02-20 12:15:44 【问题描述】:让我用一个例子来说明我的问题。
假设我有一堆非常简单的结构,像这样:
struct A
int x;
;
struct B
float y;
bool z;
;
我有一个类将这些结构存储在向量中。它有一个添加新一批结构的方法(每个结构的数量总是相同的),它有一个通过索引访问每个结构的方法。像这样的:
class Test
public:
void Create()
A a = ;
B b = ;
_vecA.push_back(a);
_vecB.push_back(b);
A* GetA(unsigned int i)
return &_vecA[i];
B* GetB(unsigned int i)
return &_vecB[i];
private:
std::vector<A> _vecA;
std::vector<B> _vecB;
;
现在,问题是每当我在程序中添加另一个结构时,我都必须在该类中添加一堆东西。例如,如果我添加另一个结构(我们称之为 C),我必须添加另一个向量,另一个 push_back 调用,并创建 GetC() 方法。 p>
现在,我的问题是:有更好的方法吗?
这是我想到的一种方法:
class ContainerBase
public:
ContainerBase();
virtual ~ContainerBase();
virtual void Add();
;
template <typename T>
class Container : public ContainerBase
public:
// Singleton
static Container& Instance()
static Container instance;
return instance;
void Add()
T t = ;
_bag.push_back(t);
T* Get(unsigned int i)
return &_bag[i];
private:
Container();
~Container();
std::vector<T> _bag;
;
class Test
public:
template <typename T>
void Register()
_containers.push_back(&Container<T>::Instance());
void Create()
for (unsigned int i = 0; i < _containers.size(); i++)
_containers[i]->Add();
template <typename T>
T* Get(unsigned int i)
return Container<T>::Instance().Get(i);
private:
std::vector<ContainerBase*> _containers;
;
我试图通过创建一个模板类 Container 来管理每种类型的向量来解决这个问题。如您所见,它涉及使用单例模式来确保对于特定类型的结构总是有一个 Container。结构的类型只需要使用 Register 方法注册到类中,以便 Test 知道应该添加新结构的 Containers to,当创建新批次时。这个解决方案是有问题的,因为它向容器引入了全局状态,并且这样做使得不可能创建 Test 类的两个实例,它们不为特定类型的结构共享它们的向量。如果我不将容器设为单例,那么我将无法通过 Test 的 Get 函数中的类型来访问它们,我必须知道 _containers 中的哪个索引向量对应什么类型的容器。
我觉得应该有更好的方法来做到这一点。
【问题讨论】:
vector <template>, c++, class, adding to vector的可能重复 【参考方案1】:使用基类,使 A、B 和 C 派生自该基类,并仅保留基类向量。它叫polymorphism。
【讨论】:
那个,或者让容器类也成为模板,就像vector
一样。
我需要为每种结构类型设置单独的向量。这对我的程序至关重要。只有一个向量会使仅遍历一种类型的结构变得困难。
然后为每种类型保留一个向量以下将解决您的问题(需要 C++11)
#if 1 // std::get<T>(tuple) is not in C++11
// Helper to retrieve index to be able to call std::get<N>(tuple)
template <typename T, typename ... Ts> struct get_index;
template <typename T, typename ... Ts>
struct get_index<T, T, Ts...> : std::integral_constant<std::size_t, 0> ;
template <typename T, typename Tail, typename ... Ts>
struct get_index<T, Tail, Ts...> :
std::integral_constant<std::size_t, 1 + get_index<T, Ts...>::value> ;
#endif
template <typename ... Ts>
class Data
public:
void Create()
int dummy[] = 0, (getVector<Ts>().emplace_back(), 0)...;
static_cast<void>(dummy); // silent warning about unused variable
template <typename T>
const T* Get(std::size_t i) const return &getVector<T>()[i];
template <typename T>
T* Get(std::size_t i) return &getVector<T>()[i];
private:
template <typename T>
const std::vector<T>& getVector() const return std::get<get_index<T, Ts...>::value>(items);
template <typename T>
std::vector<T>& getVector() return std::get<get_index<T, Ts...>::value>(items);
private:
std::tuple<std::vector<Ts>...> items;
;
测试一下:
class A;
class B;
int main()
Data<A, B> d;
d.Create();
const B* b = d.Get<B>(0);
return 0;
【讨论】:
这看起来可能是一个更好的解决方案。虽然我不太明白 get_index 发生了什么。我得再仔细研究一下。 一个问题,你为什么在 Get 方法中返回 T& 而不是指针? 我更喜欢尽可能返回参考。如果你愿意,你可以返回指针。get_index
是一个元编程,用于在T1, T2, T3, ..., TN
中检索T
类型的索引。因为在 C++11 中,std::get<T>(tuple)
不可用(应该在 C++1y 中)。
有没有办法修改它,以便相同的类型在内存中打包在一起? AAABBBCCC 代替 ABCABCABC。至少我猜现在是 ABCABCABC 这会提高缓存的一致性,因为当我迭代时,大多数时候我都是在同一个类型上做的。【参考方案3】:
这就是我最终解决问题的方法。
我创建了一个 ContainerMapper 类,它具有不同结构类型的映射(使用 typeinfo 获取类型),每个类型都映射到该类型的模板化容器。
std::map<const std::type_info*, ContainerBase*> _map;
我还保留了所有已注册类型的向量,以便在需要时对它们进行迭代。
std::vector<const std::type_info*> _types;
要注册新类型,我调用 CointainerMapper 的 Register() 方法:
template <typename T>
void Register()
_types.push_back(&typeid(T));
_map[&typeid(T)] = new Container<T>;
为了访问它们,我使用:
template <typename T>
Container<T>* Get()
return (Container<T>*)_map[&typeid(T)];
容器代码与问题示例中的相同。
当我想创建另一批结构时,我只需遍历已注册的类型,获取映射的容器并调用它们的 Add() 方法。
for (unsigned int i = 0; i < _types.size(); i++)
_map[_types[i]]->Add();
使用所有这些看起来像这样:
ContainerMapper m;
m.Register<A>();
m.Create();
// Get container
Container<A>* cA = m.Get<A>();
// Get first element
A* a = cA->Get(0);
// Set x member variable
a->x = 4;
// Or shorter way
m.Get<A>()->Get(0)->x = 4;
【讨论】:
以上是关于向类添加额外的向量的主要内容,如果未能解决你的问题,请参考以下文章