练手的 [定义] auto_array<typename T, std::size_t dim, typename Allocator = _test_allocator<T> > a; 第一个参数是元素类型,第二个是最高维度,维度标记从0到dim-1,第三个是一个分配器 [重塑数组大小] reshape(std::size_t dim_index, std::size_t width, long start = 0); 第一个参数是指定第几维,第二个参数是指定该维的宽度,第三个参数是起始下标. 这个函数可以重叠使用,如 a.reshape(0,4);a.reshape(1,5); 等价于 a.reshape(0,4)(1,5); [operator[]操作] 和C语言的数组[]操作一样,没有任何不同,只是多了运行时越界检查. 测试代码(编译环境Dev C++(GCC)): #include <iostream>#include "auto_array.hpp" using namespace std; int main(int argc, char *argv[]){ auto_array<int,1> a; a.reshape(0,5); try { a[0]=1; a[0]+=2; a[1]=3; a[4]=a[0]*a[1]; } catch(runtime_error &err) { cout<<err.what()<<endl; system("PAUSE"); return 0; } //auto_array<int,2> a; //a.reshape(0,4)(1,5); //a[3][0]=1; if(!a.empty()) cout<<"a is not null"<<endl; cout<<a[0]<<endl <<a[1]<<endl <<a[2]<<endl; cout<<a.size()<<endl <<a.max_size()<<endl; a=0; if(!a) cout<<"a is null now"<<endl; system("PAUSE"); return EXIT_SUCCESS;} 下一步,设计一个和boost::multi_array类似的'生成器',以下是源码,版权所有: #ifndef AUTO_ARRAY#define AUTO_ARRAY #include <stdexcept> //test allocatortemplate<typename T>class _test_allocator{public: static void* allocate(std::size_t n) { return malloc(n*sizeof(T)); } static void deallocate(void* p, std::size_t /* __n */) { free(p); } static void* reallocate(void* __p, std::size_t /* old_sz */, std::size_t __new_sz) { return realloc(__p, __new_sz*sizeof(T)); }}; struct range_list{ long start; std::size_t width; std::size_t step;}; template<typename T, std::size_t dim, typename Allocator = _test_allocator<T> >class auto_array{public: typedef T value_type; typedef value_type* pointer; typedef const value_type* const_pointer; typedef value_type* iterator; typedef const value_type* const_iterator; typedef value_type& reference; typedef const value_type& const_reference; typedef size_t size_type; typedef ptrdiff_t difference_type; auto_array() : range_changed(false), data(0), length(0), max_sz(0) { for(std::size_t i=0;i<dim;++i) rl[i].width=0; } template<std::size_t _dim> class reshape_functor { public: reshape_functor(range_list *prl) : rl(prl) {} reshape_functor operator()(std::size_t dim_index, std::size_t width, long start = 0) { if(dim_index>=_dim) throw(std::runtime_error("array reshape error: dimensionality too big")); rl[dim_index].start=start; rl[dim_index].width=width; return *this; } private: range_list *rl; }; reshape_functor<dim> reshape(std::size_t dim_index, std::size_t width, long start = 0) { range_changed=true; return reshape_functor<dim>(rl)(dim_index,width,start); } template<typename _T, std::size_t _dim> class index_functor { public: index_functor(_T *pdata, const range_list *prl) : data(pdata), rl(prl) {} index_functor<_T,_dim-1> operator[](long index) { if(index>=rl[0].start && index-rl[0].start<static_cast<long>(rl[0].width)) return index_functor<_T,_dim-1>(data+(index-rl[0].start)*rl[0].step,rl+1); else throw(std::runtime_error("array access error: out of bound")); } private: _T *data; const range_list *rl; }; template<typename _T> class index_functor<_T,0> { public: index_functor(_T *pdata, const range_list *prl) : data(pdata) {} operator _T(){ return data[0]; } template<typename U> _T& operator=(const U &other){ return data[0]=other; } template<typename U> _T& operator+=(const U &other){ return data[0]+=other; } template<typename U> _T& operator-=(const U &other){ return data[0]-=other; } template<typename U> _T& operator*=(const U &other){ return data[0]*=other; } template<typename U> _T& operator/=(const U &other){ return data[0]/=other; } template<typename U> _T& operator%=(const U &other){ return data[0]%=other; } template<typename U> _T& operator<<=(const U &other){ return data[0]<<=other; } template<typename U> _T& operator>>=(const U &other){ return data[0]>>=other; } template<typename U> _T& operator^=(const U &other){ return data[0]^=other; } template<typename U> _T& operator&=(const U &other){ return data[0]&=other; } template<typename U> _T& operator|=(const U &other){ return data[0]|=other; } private: _T *data; }; index_functor<T,dim-1> operator[](long index) { if(getready()) return index_functor<T,dim>(data,rl)[index]; else throw(std::runtime_error("array access error: shape uninitialized")); } struct dummy{void nonnull(void){}}; typedef void (dummy::*safe_bool)(void); operator safe_bool() {return data==0?0:&dummy::nonnull;} bool empty() const {return data==0;} size_type size() const { return length; } size_type max_size() const { return max_sz; } void clear() { if(data) { deallocate(data,max_sz); data=0; max_sz=0; } } void operator=(int zero){ clear(); } iterator begin() { return data; } const_iterator begin() const { return data; } iterator end() { return data+length; } const_iterator end() const { return data+length; } private: pointer allocate(std::size_t n){ return static_cast<pointer>(Allocator::allocate(n)); } void deallocate(pointer p, std::size_t sz){ Allocator::deallocate(static_cast<void*>(p),sz); } pointer reallocate(pointer p, std::size_t _old_sz, std::size_t _new_sz){ return static_cast<pointer>( Allocator::reallocate(static_cast<void*>(p),_old_sz,_new_sz) ); } bool getready(); private: range_list rl[dim]; bool range_changed; T* data; std::size_t length; std::size_t max_sz;}; template<typename T, std::size_t dim, typename Allocator>bool auto_array<T,dim,Allocator>::getready(){ if(range_changed) { std::size_t _new_length=1; for(long i=dim-1;i>=0;--i) { _new_length*=rl[i].width; rl[i].step = (i+1==dim?1:rl[i+1].step*rl[i+1].width); } if(_new_length>max_sz) { do{ max_sz = (max_sz==0?128:(max_sz<<1)); }while(_new_length>max_sz); if(data) data=reallocate(data,0,max_sz); else data=allocate(max_sz); } length=_new_length; range_changed=false; } return length>0;} #endif // by rickone 2008/02/18

评论