BREW vector(3)
昨日の
プログラムの、どこが問題だったかというと、
_Ufill( v._First , _N , _V );
この部分です。
この関数の実装は、
void _Ufill( iterator _F , size_type _N , const _Ty &_X ){ for( ; 0 < _N ; --_N , ++_F ){ // allocatorは使用しない // allocator.construct( _F , _X ); operator new( (void*)_F ) _Ty( _X ); } }
こうなっています。
_Ufillの内部で、コピーコンストラクタを実行しているわけです。
なので、当然コンパイラは、どの型のコピーコンストラクタを実行するか、というのを知っている必要があるのですが、vector_proxyはvoid*型のメンバしか持っていないため、うまく動作しません。
そこで、仮想関数を使って実装することを考えてみます。
まず、
class functor_base{ public: virtual void operator()() = 0; };
functorの仮想関数を作っておいて、型に依存する関数を、テンプレートクラスとして実装します。
template< class _Ty > class _Ufill_functor : public functor_base{ public: _Ufill_functor( _Ty*& _P , size_t& _N , const _Ty& _X ) : P( _P ) , N( _N ) , X( _X ){} void operator()(){ _Ty* P_ = P; for( ; 0 < N ; --N , ++P_ ){ new( P_ ) _Ty( X ); } } private: _Ty*& P; size_t& N; const _Ty& X; };
値渡しだと、functorを作成した瞬間に値が束縛されてしまい、まだ値が入っていないオブジェクトに対してfunctorを実行してしまうので、参照渡しにしています。
こうすれば、実行した瞬間の値が適用されることになります。
で、委譲する側は、functorを作って、それをvector_helperに渡し、委譲される側はいつものように実行するだけです。
あと、functorは参照渡しかポインタ渡しにしないと、スライシングが発生するので注意です。
explicit vector( size_type _N , const _Ty& _V = _Ty() ){ functor_base& _Ufill = _Ufill_functor< _Ty >( _First , _N , _V ); vector_helper::constructor( *(vector_proxy*)this , sizeof( _Ty ) , _N , _Ufill ); }
class vector_helper{ static void constructor( vector_proxy& v , size_type n , size_type _N , functor_base& _Ufill ){ v._First = _allocate( n , _N ); // functor実行 // 引数は内部に保持している _Ufill(); v._Last = (void*)((byte*)v._First + n * _N); v._End = v._Last; } };
出来たヽ(´ー`)ノ
……ええ、出来ました。出来たんですよ、確かに。
(面倒ですが)この方法で全てのメソッドを実装することが可能です。
しかし!
逆に容量増えます
もうこれは笑うしかないね(´▽`*)アハハ
ぶっちゃけ作ってるときは気が付きませんでした(;´Д`)
数時間掛けて作ったプログラムがゴミ箱行き……あゝ無情……。
ということで、別の方法を考えることになります。