向类中添加其他向量

时间:2014-02-20 12:15:44

标签: c++ vector struct

让我用一个例子来证明我的问题。

让我们说我有一堆非常简单的结构,如:

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()方法。

现在,我的问题是:有更好的方法吗?

这是我想到的一种方式:

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 它应该添加新的结构到,创建新批次时。这个解决方案存在问题,因为它将全局状态引入容器,这样就无法创建 Test 类的两个实例,它们不会为某种类型的结构共享它们的向量。如果我没有制作容器单例,那么我无法通过 Test 的Get函数中的类型访问它们,我将不得不知道哪个索引在_ 容器 vector对应于什么类型的容器。

我觉得应该有更好的方法来做到这一点。

3 个答案:

答案 0 :(得分:0)

使用基类,使A,B和C派生自该基类,并仅保留基类向量/向量。它被称为polymorphism

答案 1 :(得分:0)

以下将解决您的问题(需要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;
}

答案 2 :(得分:0)

以下是我最终解决问题的方法。

我创建了一个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;