C++标准库提供了string、array、和vector,他们是一维数组,另有个组间valvarry可以实现多维的数值数组,但他不是容器,而且设计存在一些问题。多维数组虽然实际应用中没有一维数组那么普遍,但也是很有用的。在C++中除了原始数组,只能用vector<vector<T>>来代替了,虽然可用,但不太方便。
multi—array库解决了这个问题,它是一个多维容器,高效地实现了STL风格的多维数组,比使用原始多维数组或者vector of vector更好。
类摘要
multi_array很像标准容器,具有标准容器的大部分接口,它的类摘要如下:
template <typename Valuetype, std::size_t NumDims>
class multi_array
{
public:
/// 内部类型定义
template <std::size_t Dims> struct subarray;
template <std::size_t Dims> struct const_subarray;
template <std::size_t Dims> struct array_view;
template <std::size_t Dims> struct const_array_view;
multi_array();
explicit multi_array(const ExtentList& size, const storage_order_type& store = c_storage_order());
explicit multi_array(const extents_tuple& ranges, const storage_order_type& store = c_storage_order());
iterator begin();///迭代器
iterator end();
size_type size()const;
size_type num_elements()const;
size_type num_dimensions()const;
reference operator[](index i);/// 重载operator[]
element& operator()(const IndexList& indices);
array_view<Dims>::type operator[](const indices_tuple& r);
const_array_view<Dims>::type operator[](const indices_tuple& r)const;
element* data();///维度操作
element* origin();
const element* origin()const;
const size_type* shape()const;
const index* strides()const;
const index* index_bases()const;
const storage_order_tpye& storage_order()const;
bool operator==(const multi_array& rhs);
void reshape(const SizeList& sizes);
void assign(InputIterator begin, InputIterator end);
void reindex(const BaseList& values);
void reindex(index value);
multi_array& resize(const extentList& extents);
multi_array& resize(extents_tuple& extents);
};
multi_array 是递归定义的,它的每个维度都是一个multi_array,最底层的则是一个一维的multi—array,因此multi-array是组个模式的一个具体应用
用法
multi_array<int, 3> ma;
定义了一个三维数组ma,相当于int ma[x][y][z].
但仅仅指定了维数还是不够,多维数组还需要指定维度的具体值。
multi—array为了完成这个任务特意提供了extent—gen类和预定义的一个实例boost::extents,它重载了operator[],用起来就像一个原始多维数组,例如:
multi_array<int, 3> ma(extents[2][3][4]);
多维数组的总维度可以用成员函数num_dimensions()获得,它的返回值就是模板参数中的NumDims. 函数shape()返回一个常量指针(数组),里面有NumDims个元素,表明了具体各个维度的值。
/// 申明一个3维数组
multi_array<int, 3> ma(extents[2][3][4]);
auto shape = ma.shape();
for (size_t i = 0; i < ma.num_dimensions(); ++i)
{
cout << shape[i] << ",";
}
cout << endl << ma.num_elements() << endl;
/// 可以像普通数组一样遍历
for (int i = 0, v = 0; i < 2; ++i)
for (int j = 0; j < 3;++j)
for (int k = 0;k < 4;++k)
{
ma[i][j][k] = v++;
}
/// 输出多维数组内所有元素
for (int i = 0; i < 2; ++i)
{
for (int j = 0; j < 3;++j)
{
for (int k = 0;k < 4;++k)
{
cout << ma[i][j][k] << ",";
}
cout << endl;
}
cout << endl;
}
//cout << ma[2][3][4];
std::array<size_t, 3> idx = {0,1,2};/// 使用array
ma(idx) = 10; /// 使用operator()
cout << ma(idx) << endl;
改变形状和大小
multi—array可以在运行时使用成员函数reshape()改变多维数组的形状,即变动各维度的大小,但总维度和元素数量保持不变,变动前的维度乘积与变动后的维度乘积必须相等
multi_array<int, 3> ma(extents[2][3][4]);
assert(ma.shape()[0] == 2);
std::array<std::size_t, 3> arr = {4,3,2};
ma.reshape(arr); /// [2][3][4]->[4][3][2]
assert(ma.shape()[0] == 4);
ma.resize(extents[2][9][9]);
assert(ma.num_elements() == 2*9*9);
assert(ma.shape()[1] == 9);
创建子视图
多维数组的操作是比较复杂的,multi_array库允许用户为多维数组创建一个只查看其中一部分数据的子视图(view),子视图即可以与原始数组拥有相同的维数,也可以少于原来的维数。
typedef multi_array<int, 2> ma_type;
multi_array<int, 2> ma(extents[3][4]) ;
typedef ma_type::index_range range;
//indices[range(0,2)][range(0,2)];
///需要用index_gen类的预定义的实例indices来
///定义子视图的索引
auto view = ma[indices[range(0,2)][range(0,2)] ];
cout << view.num_elements() << endl;
for (int i = 0; i < 2; ++i)
{
for (int j = 0; j < 2;++j)
{
cout << view[i][j] << ",";
}
cout << endl;
}
cout << *view.shape() << endl;