Initializing a member variable STL vector through a class constructor

跟風遠走 提交于 2021-01-27 18:04:17

问题


I have the following code which seems to work:

class MapCell
{
    public:
    int x, y, z;
};

void Test3DVector(int size_x, int size_y, int size_z)
{
    vector< vector< vector<MapCell> > > m(size_x, vector<vector<MapCell>>(size_y, vector<MapCell>(size_z)));

    for (int x = 0; x < size_x; ++x)
    {
        for (int y = 0; y < size_y; ++y)
        {
            for (int z = 0; z < size_z; ++z)
            {
                m[x][y][z].x = x;
                m[x][y][z].y = y;
                m[x][y][z].z = z;
            }
        }
    }
}

I want to write a class that has the 3D vector as a member variable, with the dimensions set in the constructor, like so:

class MyClass
{
    public:
        vector< vector< vector<MapCell>>> m;    // I'm not sure how to write this
    MyClass::MyClass(int size_x, int size_y, int size_z)
    {
        // Do the same initialization as Test3DVector did.

    }
 };

So that I can do something like this:

void SomeFunction()
{
   MyClass grid(5, 5, 5);
   cout << grid->m[1][3][2].x << grid->m[1][3][2].y << grid->m[1][3][2].z << endl;
   // Should output 132
}

What is the best way to do this? When the vectors become very large are there any common mistakes that I should avoid to get the best speed?


回答1:


updated with a variadic version

1. Simple, explicit code

class MyClass {
public:
    vector<vector<vector<MapCell>>> m;
    MyClass(int size_x, int size_y, int size_z)
        : m(size_x,
            vector<vector<MapCell> >(
                size_y,
                vector<MapCell>(size_z)
            )
           ) {
    }
};

2. With a helper

class MyClass {
    vector<vector<vector<MapCell>>> m;
public:
    MyClass(int size_x, int size_y, int size_z)
        : m(Dim(size_z, Dim(size_y, Dim(size_x, MapCell())))) {
    }

private:
    template <typename T>
    static std::vector<T> Dim(size_t n, T&& v) {
        return std::vector<T>(n, std::move(v));
    }
};

3. With a variadic helper

Because variadics are funadic! here is a version using variadics to make things ... prettier (depending on taste):

struct MyClass
{
    vector<vector<vector<MapCell>>> m;
    MyClass(int size_x, int size_y, int size_z)
        : m(vec_matrix(MapCell(), size_z, size_y, size_x))
    { }

private:
    template <typename T> static std::vector<T> vec_matrix(T v, size_t n) {
        return { n, std::move(v) };
    }

    template <typename T, typename... Dim> static auto vec_matrix(T v, size_t n, Dim... other)
        -> std::vector<decltype(vec_matrix(v, other...))> {
        return { n, vec_matrix(v, other...) };
    }
};

PS. I have slightly edited the code to be more standards-compliant. There is a subtle issue with templates and trailing-return-type that refers to an overload of the same name. For a nice breakdown of the issue here, see this discussion bookmark in chat

In case your compiler doesn't believe it should work, see it live on gcc 4.7.2. It uses boost only to format the output:

. . . .
. . . .
. . . .
. . . .
. . . .
-------
. . . .
. . . .
. . . .
. . . .
. . . .

Full code to avoid link-rot on SO:

#include <iostream>
#include <vector>
#include <boost/spirit/include/karma.hpp> // for debug output only

using namespace std;

struct MapCell 
{
    friend std::ostream& operator <<(std::ostream& os, MapCell const&)
    { return os << "."; }
};

struct MyClass
{
    vector<vector<vector<MapCell>>> m;
    MyClass(int size_x, int size_y, int size_z)
        : m(vec_matrix(MapCell(), size_z, size_y, size_x))
    { }

private:
   ///////////////////////////////////////////////////
   // variadics are funadic!
   template <typename T> static std::vector<T> vec_matrix(T v, size_t n) 
   {
      return { n, std::move(v) };
   }

   template <typename T, typename... Dim> static auto vec_matrix(T v, size_t n, Dim... other)
      -> std::vector<decltype(vec_matrix(v, other...))> 
   {
      return { n, vec_matrix(v, other...) };
   }
   ////////////
};

int main()
{
    MyClass a(4,5,2);

    using namespace boost::spirit::karma;
    std::cout 
        << format(stream % ' ' % eol % "\n-------\n", a.m) 
        << std::endl;
}


来源:https://stackoverflow.com/questions/12794397/initializing-a-member-variable-stl-vector-through-a-class-constructor

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!