C++:生成未知深度的多维矢量



我在C++中有一个函数(调用它"weightmatrix"(,它将大小为 n 的向量作为输入,其中包含一系列数字 a、b、c...,并返回由大小为 c、b、a

...

这听起来很复杂。基本上,在实践中它应该看起来像这样:

vector<int> vector_sizes = {2, 3, 1}; 
cout << "Resulting matrix: " << weightmatrix(vector_sizes); // Function takes vector of size 3
/* Returns the following 3 dimensional matrix:
   { { {0, 0}, 
       {0, 0}, 
       {0, 0} }, 
    {0, 0, 0} }
*/

我知道这很奇怪。我只需要生成一个向量,而事先不知道它将有多少维。你能以我的方式提供的任何帮助或建议都会很棒。

这是一个使用模板的解决方案 MultiVector 类从它的operator[]返回MultiVectorView

基础数据存储在纯std::vector中,但可以使用vec[x][y][z]语法进行访问。

没有检查正确的用法,只实现了非常基本的功能,但它给出了如何完成的想法。

#include <iostream>
#include <vector>
template <typename T>
class MultiVector;
template <typename T>
class MultiVectorView {
public:
    MultiVectorView(MultiVector<T>& vec_, int index_, int dimension_) : vec(vec_), index(index_), dimension(dimension_) {}
    MultiVector<T>& vec;
    int index;
    int dimension;
    MultiVectorView& operator[](std::size_t n_index) {
        int index_multiplyer = 1;
        for (int i=0; i<dimension; ++i)
            index_multiplyer *= vec.dimensions[i];
        index += n_index*index_multiplyer;
        dimension++;
        return *this;
    }
    operator T() {
        return vec.content[index];
    }
    MultiVectorView& operator=(T val) {
        vec.content[index] = val;
        return *this;
    }
};
template <typename T>
class MultiVector {
public:
    MultiVector(std::vector<int> dimensions_) : dimensions(dimensions_) {
        int size = dimensions[0];
        for (int i = 1; i<dimensions.size(); ++i)
            size *= dimensions[i];
        content.resize(size);
    }
    MultiVectorView<T> operator[](std::size_t index) {
        return MultiVectorView<T>(*this, index, 1);
    }
    std::vector<T> content;
    std::vector<int> dimensions;
};
int main() {
    std::vector<int> v = {2,3,2};
    MultiVector<int> test(v);
    int tmp = 0;
    for (int x = 0; x < v[0]; ++x)
        for (int y = 0; y < v[1]; ++y)
            for (int z = 0; z < v[2]; ++z) {
                test[x][y][z] = tmp++;
            }
    for (int i=0; i<test.content.size(); ++i)
        std::cout << std::endl << test.content[i] << " ";
    int b = test[1][2][1];
    std::cout << std::endl << "b = " << b << std::endl << "test[0][1][1] = " << test[0][1][1] << std::endl;
}

我接受了 Galik 的暗示,做了一个小样本:

#include <cassert>
#include <iostream>
#include <vector>
template <typename ELEM>
class NDArrayT {
  private:
    // dimensions
    std::vector<size_t> _dims;
    // data
    std::vector<ELEM> _data;
  public:
    NDArrayT(const std::vector<size_t> &dims):
      _dims(dims)
    {
      size_t size = _dims.empty() ? 0 : 1;
      for (size_t dim : _dims) size *= dim;
      _data.resize(size);
    }
    NDArrayT(
      const std::vector<size_t> &dims,
      const std::vector<ELEM> &data):
      NDArrayT<ELEM>(dims)
    {
      assert(_data.size() == data.size());
      std::copy(data.begin(), data.end(), _data.begin());
    }
    ELEM& operator[](const std::vector<size_t> &indices)
    {
      size_t i = 0, j = 0;
      for (size_t n = _dims.size(); j < n; ++j) {
        i *= _dims[j]; i += indices[j];
      }
      return _data[i];
    }
    const ELEM& operator[](const std::vector<size_t> &indices) const
    {
      size_t i = 0, j = 0;
      for (size_t n = _dims.size(); j < n; ++j) {
        i *= _dims[j]; i += indices[j];
      }
      return _data[i];
    }
};
using namespace std;
ostream& operator<<(ostream &out, const vector<size_t> &values)
{
  const char *sep = "";
  for (size_t value : values) {
    out << sep << value; sep = ", ";
  }
  return out;
}
bool inc(vector<size_t> &indices, const vector<size_t> &dims)
{
  for (size_t i = indices.size(); i--;) {
    if (++indices[i] < dims[i]) return false;
    indices[i] = 0;
  }
  return true; // overflow
}
int main()
{
  // build sample data
  vector<double> data(2 * 3 * 4);
  for (size_t i = data.size(); i--;) data[i] = (double)i;
  // build sample array
  typedef NDArrayT<double> NDArrayDouble;
  const vector<size_t> dims = { 2, 3, 4 };
  NDArrayDouble a(dims, data);
  // print sample array (check subscript)
  vector<size_t> indices(dims.size(), 0);
  do {
    cout << "a[" << indices << "]: " << a[indices] << endl;
  } while (!inc(indices, dims));
  // done
  return 0;
}

ideone 上编译和测试。输出为:

a[0, 0, 0]: 0
a[0, 0, 1]: 1
a[0, 0, 2]: 2
a[0, 0, 3]: 3
a[0, 1, 0]: 4
a[0, 1, 1]: 5
a[0, 1, 2]: 6
a[0, 1, 3]: 7
a[0, 2, 0]: 8
a[0, 2, 1]: 9
a[0, 2, 2]: 10
a[0, 2, 3]: 11
a[1, 0, 0]: 12
a[1, 0, 1]: 13
a[1, 0, 2]: 14
a[1, 0, 3]: 15
a[1, 1, 0]: 16
a[1, 1, 1]: 17
a[1, 1, 2]: 18
a[1, 1, 3]: 19
a[1, 2, 0]: 20
a[1, 2, 1]: 21
a[1, 2, 2]: 22
a[1, 2, 3]: 23

在连续内存中管理多维数组的"算术"实际上非常简单。我想,这个样本最"革命性"的想法是使用std::vector<size_t>为每个维度提供索引的operator[]()

当我写下这篇文章时,我想到了很多索引的替代方案。 – 幻想的空间很大...

例如,对于线性(一维(访问,也可以提供用于size_t的第二个operator[]