向类添加额外的向量

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一样。 我需要为每种结构类型设置单独的向量。这对我的程序至关重要。只有一个向量会使仅遍历一种类型的结构变得困难。 然后为每种类型保留一个向量,也可能在一个向量中,这样您就可以迭代您的一种类型的结构,或者相当容易地添加一个新类型。 @WeaselFox 我怎么知道哪个向量 用于哪个类型。 使用枚举可能......或者你真正想要的任何其他方式,这种超出了问题的限制。【参考方案2】:

以下将解决您的问题(需要 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&lt;T&gt;(tuple) 不可用(应该在 C++1y 中)。 有没有办法修改它,以便相同的类型在内存中打包在一起? AAABBBCCC 代替 ABCABCABC。至少我猜现在是 ABCABCABC 这会提高缓存的一致性,因为当我迭代时,大多数时候我都是在同一个类型上做的。【参考方案3】:

这就是我最终解决问题的方法。

我创建了一个 ContainerMapper 类,它具有不同结构类型的映射(使用 typeinfo 获取类型),每个类型都映射到该类型的模板化容器。

std::map<const std::type_info*, ContainerBase*> _map;

我还保留了所有已注册类型的向量,以便在需要时对它们进行迭代。

std::vector<const std::type_info*> _types;

要注册新类型,我调用 CointainerMapperRegister() 方法:

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;

【讨论】:

以上是关于向类添加额外的向量的主要内容,如果未能解决你的问题,请参考以下文章

二维向量下标超出范围

根据额外参数对向量进行排序

在R中添加带有条件的向量元素

上采样:在向量的每个连续元素之间插入额外的值

返回一个已知大小的向量而不需要额外的包装器?

将向量从二进制强制转换为“as.numeric”时保留名称?