发信人: RoachCock (chen3feng), 信区: Programming 标 题: cfc::array,一个多维数组类 发信站: BBS 水木清华站 (Wed May 29 10:46:42 2002)
cfc::array boost提供了boost::array,但是那只是一维的数组,我实现的这个支持一维,二维和三 维数组,三维以上的没有支持,我想你大概也不大会用到吧?:) 用标准STL容器vector来实现多维数组的话,空间是不连续的,用boost::array实现多维 数组的话,空间是连续的,但是boost的array没有基接口. 我提供的数组类同时支持我实现的这个支持一维,二维和三维数组,提供了所有数组的 基类array_base,一维数组的基类array_1d_base,二维数组的基类array_2d_base,三维数 组的基类array_3d_base,这就解决了C中多维数组的参数传递麻烦的问题. 该模板类实现了STL接口,可以像使用STL容器一样使用它.由于我对STL了解不过,实现的 也许不好,欢迎不吝斧正 同时实现了[]和()运算符,实现()运算符的原因是它再多为数组的情况下比[]要高效的 多.使用()的原因是受Basic语言的影响 对于每一维数组本身和基类的,我都提供了不同版本的实现,例如在基类array_2d_base 中,我用乘法实现(),而在array_2d中,我用原始数组的[]来实现, 这好像违背了不覆盖基类非虚函数的原则,其实不然,因为派生类中的重载做的是和基 类中完全一样的动作,但是却是优化的版本,而且基类的版本不算很低效,没必要用虚 函数,因为这样可能更慢而且不利于内联化.这样做的唯一原因就是为了效率. 还需要注意的是,由于MSVC模板实现的不好,有些特性还不适用,例如VC把模板中的数组 引用的定义视为错误,因为它把数组的大小看作0,而指针就没事,暂时还没解决 我还写了一个 dynamic_array<typename T,int dim=1>类,根据dim分别派生于 array_1d_base,array_2d_base,array_3d_base还没调试好,等好了,而且本文没有受 到大家唾弃的话在post吧.还有share_array...任重而道远,以后再说吧. 所有的类定义于namespace cfc,meams chen feng's class libraries. 你会在我的源代码中看到boost::function和boost::array的影子,感谢boost! 模板类的使用很简单: #include "cfc/array.h" using namespace cfc; void foo(array_1d_base<int> & a) { a[0]+=10; } int main() { array<int ,10> a1;//一维数组 array<int ,10, 10> a2;//二维数组 array<int ,10, 10, 10> a3;//二维数组 a1[0]=10; a1(0)=10; //Basic风格 a3[0](1,1)=10; a3[0][0](0)=10; foo(a1); foo(a2[0]); foo(a3[0][0]); }
这是源程序:
使用了根据模板参数选择基类从而可以实例化生成有较大差别的类的手法, :) file://array.h ,array类和其的实现 #ifndef _ARRAY_H_ #define _ARRAY_H_ #ifdef _MSC_VER #define CFC_STATIC_CONST(type, assign) enum{assign} #else #define static const type assign #endif #include "arrays.h" namespace cfc { namespace detail { namespace array { template <int n> struct real_get_impl { }; template <> struct real_get_impl<1> { template<typename T, int d1, int d2, int d3> struct dimensions { typedef array_1d<T, d1> type; }; }; template <> struct real_get_impl<2> { template <typename T, int d1, int d2, int d3 > struct dimensions { typedef array_2d<T, d1, d2> type; }; }; template <> struct real_get_impl<3> { template <typename T, int d1, int d2, int d3 > struct dimensions { typedef array_3d<T, d1, d2, d3> type ; }; }; template <typename T, int d1, int d2, int d3> struct get_impl { CFC_STATIC_CONST(int, value = int(d2!=-1) + int(d3!=-1) + 1 ); typedef typename real_get_impl<value>:: template dimensions<T, d1, d2, d3>:: type type; }; } } template <typename T, int d1, int d2 = -1, int d3 = -1> class array : public detail::array::get_impl<T, d1, d2, d3>::type { typedef typename detail::array:: get_impl<T, d1, d2, d3>::type base_type; public: array(){} }; } #endif file://_ARRAY_H_ // array_base.h #ifndef _ARRAY_BASE_H_ #define _ARRAY_BASE_H_ #include <cstddef> #include <iterator> #include <algorithm> #include <stdexcept> namespace cfc { template <typename T> class array_base { public: typedef T value_type; typedef T* iterator; typedef const T* const_iterator; typedef T& reference; typedef const T& const_reference; typedef /*std*/::size_t size_type; typedef /*std*/::ptrdiff_t difference_type; #ifdef _MSC_VER typedef std::reverse_iterator<iterator,T> reverse_iterator; typedef std::reverse_iterator<const_iterator,T> const_reverse_iterat or; #else typedef std::reverse_iterator<iterator> reverse_iterator; typedef std::reverse_iterator<const_iterator> const_reverse_iterator ; #endif public: iterator begin() { return pdata; } const_iterator begin() const { return pdata; } iterator end() { return pdata + size(); } const_iterator end() const { return pdata + size(); } reverse_iterator rbegin() { return reverse_iterator(end()); } const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } reverse_iterator rend() { return reverse_iterator(begin()); } const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } // at() with range check reference at(size_type i) { rangecheck(i); return pdata[i]; } const_reference at(size_type i) const { rangecheck(i); return elems[ i]; } // front() and back() reference front() { return pdata[0]; } const_reference front() const { return pdata[0]; } reference back() { return pdata[size()-1]; } const_reference back() const { return pdata[size()-1]; } // size is constant bool empty() { return pdata != 0; } size_type max_size() { return size(); } // swap (note: linear complexity) file://void swap (array<T,N>& y) { // std::swap_ranges(begin(),end(),y.begin()); file://} // direct access to data const T* data() const { return pdata; } size_type size() const { int sum=1; for(int i=0;i<dim_count;i++) sum*=dims[i]; return sum; } void assign (const T& value) { std::fill_n(begin(),size(),value); } void swap (array_base<T>& y) { if(size() != y.size())throw std::length_error("array "); std::swap_ranges(begin(),end(),y.begin()); } template <typename T2> array_base<T>& operator= (const array_base<T2>& rhs) { std::copy(rhs.begin(),rhs.end(), begin()); return *this; } size_t get_dims(size_t index){return dims[i];} void rangecheck (size_type i) { if (i >= size()) { throw std::range_error("array"); } } protected: array_base(){} protected: T * pdata; int dim_count; int dims[3]; array_base(int d):dim_count(d){} }; // comparisons template<class T1,class T2> bool operator== (const array_base<T1>& x, const array_base<T2>& y) { return std::equal(x.begin(), x.end(), y.begin()); } template<class T> bool operator< (const array_base<T>& x, const array_base<T>& y) { return std::lexicographical_compare(x.begin(),x.end(),y.begi n(),,y.end()); } template<class T1,class T2> bool operator!= (const array_base<T1>& x, const array_base<T2>& y) { return !(x==y); } template<class T1, class T2> bool operator> (const array_base<T1>& x, const array_base<T2>& y) { return y<x; } template<class T1, class T2> bool operator<= (const array_base<T1>& x, const array_base<T2>& y) { return !(y<x); } template<class T1, class T2> bool operator>= (const array_base<T1>& x, const array_base<T2>& y) { return !(x<y); } // global swap() template<class T1, class T2> inline void swap (array_base<T1>& x, array_base<T2>& y) { x.swap(y); } template <typename T> class array_1d_base:public array_base<T> { public: const_reference operator [](size_type index)const { return pdata[index]; } reference operator[](size_type index) { return pdata[index]; } const_reference operator ()(size_type index)const { return pdata[index]; } reference operator()(size_type index) { return pdata[index]; } public: array_1d_base(T* pd,size_type d1) { dim_count = 1; pdata = pd; dims[0] = d1; } protected: array_1d_base() {dim_count=1;} }; template <typename T> class array_2d_base : public array_base<T> { public: const array_1d_base<T> operator[](size_type index)const { return array_1d_base<T>(pdata+index*dims[1],dims[1]) ; } array_1d_base<T> operator[](size_type index) { return array_1d_base<T>(pdata+index*dims[1],dims[1]) ; } // // Basic style access const_reference operator ()(size_type index1, size_type inde x2)cconst { return pdata[index1 * dims[1] + index2]; } reference operator()(size_type index1, size_type index2) { return pdata[index1 * dims[1] + index2]; } public: array_2d_base(T *pd,size_type d1,size_type d2) { dim_count = 2; pdata = pd; dims[0] = d1; dims[1] = d2; } protected: array_2d_base() {dim_count = 2;} }; template <typename T> class array_3d_base : public array_base<T> { public: const array_2d_base<T> operator[](size_type index)const { return array_2d_base<T>( pdata + index * dims [1] * dims[2], dims[1], dims[2]); } array_2d_base<T> operator[](size_type index) { return array_2d_base<T>( pdata + index * dims [1] * dims[2], dims[1], dims[2] ); } // // Basic style access /* const_reference operator ()( size_type index1, size_type index2, size_type index3)const { return pdata[ index1 * dims[1] *dims[2] + index2 * dims[2] + index3 ]; }*/ reference operator()( size_type index1, size_type index2, size_type index3) { return pdata[ index1 * dims[1] *dims[2] + index2 * dims[2] + index3 ]; } protected: array_3d_base() {dim_count=3;} }; } #endif file://_ARRAY_BASE_H_ /// // arrays.h, array_1d,array_2d,array_3d的实现 #ifndef _ARRAYS_H_ #define _ARRAYS_H_ #include "array_base.h" namespace cfc { template <typename T, int dim1> class array_1d : public array_1d_base<T> { public: CFC_STATIC_CONST(size_type, static_size = dim1); const_reference operator[](size_type index)const { return data[index]; } reference operator[](size_type index) { return data[index]; } // // const_reference operator()(size_type index)const { return data[index]; } reference operator()(size_type index) { return data[index]; } protected: array_1d() { pdata = &data[0]; dims[0] = dim1; } protected: T data[dim1]; }; /// // 2d template <typename T, int dim1, int dim2> class array_2d : public array_2d_base<T> { #ifndef _MSC_VER file://MSC doesn't support ref to a template array private: typedef T (&index_type)[dim2]; typedef T const (&const_index_type)[dim2]; public: const_index_type operator[](size_type index)const { return data[index]; } index_type operator[](size_type index) { return data[index]; } #endif public: CFC_STATIC_CONST(size_type, static_size = dim1 * dim2); const_reference operator()(size_type index1, size_type index 2)coonst { return data[index1][index2]; } reference operator()(size_type index1, size_type index2) { return data[index1][index2]; } protected: array_2d() { pdata = &data[0][0]; dims[0] = dim1; dims[1] = dim2; } private: T data[dim1][dim2]; }; /// // 3d template <typename T, int dim1, int dim2, int dim3> class array_3d : public array_3d_base<T> { #ifndef _MSC_VER private: typedef T (&index_type)[dim2][dim3]; typedef T const (&const_index_type)[dim2][dim3]; public: const_index_type operator[](size_type index)const { return data[index]; } index_type operator[](size_type index) { return data[index]; } #endif public: CFC_STATIC_CONST(size_type, static_size = dim1 * dim2 * dim3 ); const_reference operator()( size_type in dex1 size_type in dex2 size_type in dex3 )const { return data[index1][index2][index2]; } reference operator()( size_type index1, size_type index2, size_type index3) { return data[index1][index2][index3]; } protected: array_3d() { pdata =&data[0][0][0]; dims[0] = dim1; dims[1] = dim2; dims[2] = dim3; }
private: T data[dim1][dim2][dim3]; }; } #endif//_ARRAYS_H_ // the end.:) -- namespace cfc { class dummy{}; };