OSDN Git Service

186efcba3b277f33c97ac3921b176ff37f0d6c25
[gintenlib/gintenlib.git] / gintenlib / pointer_facade.hpp
1 #ifndef GINTENLIB_INCLUDED_POINTER_FACADE_HPP_
2 #define GINTENLIB_INCLUDED_POINTER_FACADE_HPP_
3
4 /*
5
6       <gintenlib/pointer_facade.hpp>
7
8   pointer_facade : 簡易スマートポインタ製作
9
10   宣言:
11     template< class Derived, typename T, typename Category = Derived >
12     struct pointer_facade
13     {
14       typedef T  element_type;
15       typedef T  value_type;
16       typedef T* pointer;
17       typedef T& reference;
18       
19       // 参照外しとポインタ取得
20       reference operator*() const;
21       pointer operator->() const;
22       friend pointer get_pointer( const Derived& target );
23       
24       // bool 比較
25       operator unspecified_bool_type() const;
26       bool operator!() const;
27     
28     };
29     
30     // テンプレート版相互比較
31     // カテゴリが同じものなら相互比較OK
32     template<typename T, typename U, typename D1, typename D2, typename C>
33     inline bool operator==
34       ( const pointer_facade<D1, T, C>& lhs, const pointer_facade<D2, U, C>& rhs );
35       
36     template<typename T, typename U, typename D1, typename D2, typename C>
37     inline bool operator!=
38       ( const pointer_facade<D1, T, C>& lhs, const pointer_facade<D2, U, C>& rhs );
39     
40     template<typename T, typename U, typename D1, typename D2, typename C>
41     inline bool operator<
42       ( const pointer_facade<D1, T, C>& lhs, const pointer_facade<D2, U, C>& rhs );
43   
44   機能:
45     get() さえ実装すれば、それを元にスマートポインタとして必要なものを生成するクラスです。
46     実装してくれるものは以下の通り:
47      ・element_type, value_type, pointer, reference の型定義
48      ・operator*, operator->, get_pointer() によるポインタ取得
49      ・bool値との比較、スマートポインタ同士の比較
50      ・異なる型を示すスマートポインタ同士の比較(同じカテゴリに属するもののみ)
51     
52     使い方は bool_comparable と同じ、「テンプレートに自分自身の型名を入れて継承」。
53     第二引数はポインタを格納するオブジェクトの型を示します。
54     省略可能な第三引数はポインタのカテゴリ、第三引数が同じスマートポインタ同士は相互比較できます。
55     省略した場合、他のスマートポインタとは比較が出来ません(でも通常は比較できた方が良いですよ?)。
56     さらに詳しくは、下の欄や、銀天ライブラリで定義されたスマートポインタの実装をご覧ください。
57     
58   使い方:
59     // 単純なポインタへのラッパ
60     
61     // スマートポインタを作る場合、まずカテゴリクラスを定義する。
62     // 同じ種類のスマートポインタで、同じカテゴリを共有することで、
63     // スマートポインタ同士の相互比較が(同じ種類のスマートポインタに限り)可能になる。
64     struct trivial_ptr_category {}; // カテゴリクラスはタグなので適当に
65     
66     // 本体 
67     template<typename T>
68     class trivial_ptr :
69       public gintenlib::pointer_facade< trivial_ptr<T>, T, trivial_ptr_category > // こう使う
70     {
71      public:
72       trivial_ptr() : p(0) {}
73       explicit trivial_ptr( T* ptr ) : p( ptr ) {}
74       
75       // 解放処理とか行わない
76       // ~trivial_ptr() throw () {}
77       
78       // get() さえあればOK
79       T* get() const { return p; }
80       
81       // reset とか swap もあると良いけど、基本はこれで終了!
82       
83      private:
84       T* p;
85       
86     };
87     
88     int main()
89     {
90       trivial_ptr<int> p1( new int() );
91       
92       // 色々と自動定義してくれるので
93       // こんな感じに書ける
94       if( p1 )  // OK
95       {
96         cout << *p1 << endl; // OK
97       }
98       
99       trivial_ptr<vector<int> > p2( new vector<int>() );
100       cout << p2->size() << endl; // OK
101       
102       trivial_ptr<void> p0; // void へのポインタも適切に振り分けてくれる
103       assert( p0 != p1 ); // もちろん比較できる
104       
105       // todo: delete
106     }
107   
108   注意事項:
109     ポインタに必要な機能はあらかた用意してくれる便利クラスですが、
110     static_pointer_cast やら swap やら reset やらは定義してくれません。忘れないように。
111     なお、 friend 関数の get_pointer や operator== なんかは、gintenlib 名前空間内に定義されます。
112     通常は ADL によって意識する必要はありませんが、古いコンパイラでは引っかかるかも。
113
114 */
115
116 #include "bool_comparable.hpp"
117
118 #include <cassert>
119 #include <functional> // for std::less
120 #include <boost/type_traits/add_reference.hpp>
121
122 namespace gintenlib
123 {
124   template< typename Derived, typename T, typename Category = Derived >
125   struct pointer_facade
126     : bool_comparable< pointer_facade< Derived, T, Category > >
127   {
128     // スマートポインタとして必要なあれこれ
129     typedef T  element_type;
130     typedef T  value_type;
131     typedef T* pointer;
132     // reference は void 型への対応のため特殊
133     typedef typename boost::add_reference<T>::type reference;
134     
135     // 参照外しとポインタ取得
136     reference operator*() const
137     {
138       using namespace std;
139       assert( get_() != 0 );
140       return *get_();
141     }
142     pointer operator->() const
143     {
144       using namespace std;
145       assert( get_() != 0 );
146       return get_();
147     }
148     // for boost::mem_fn
149     friend pointer get_pointer( const Derived& target )
150     {
151       return target.get();
152     }
153     
154     // bool との比較
155     bool operator!() const
156     {
157       return !get_();
158     }
159     // operator safe_bool は bool_comparable の管轄
160     
161     // 相互比較は外部で定義する
162     
163    private:
164     // 派生クラスの get() を呼び出す
165     pointer get_() const
166     {
167       return static_cast<const Derived*>(this)->get();
168     }
169     
170    protected:
171      pointer_facade(){}
172     ~pointer_facade(){}
173   
174   };  // pointer_facade<Derived, T, Category>
175   
176   // 相互比較
177   // カテゴリが同じものなら相互比較OK
178   template<typename T, typename U, typename D1, typename D2, typename C>
179   inline bool operator==( const pointer_facade<D1, T, C>& lhs, const pointer_facade<D2, U, C>& rhs )
180   {
181     return static_cast<const D1&>(lhs).get() == static_cast<const D2&>(rhs).get();
182   }
183   template<typename T, typename U, typename D1, typename D2, typename C>
184   inline bool operator!=( const pointer_facade<D1, T, C>& lhs, const pointer_facade<D2, U, C>& rhs )
185   {
186     return static_cast<const D1&>(lhs).get() != static_cast<const D2&>(rhs).get();
187   }
188   
189   // < は、ポインタ型が同じ場合とそうでない場合で分ける
190   template<typename T, typename D, typename C>
191   inline bool operator< ( const pointer_facade<D, T, C>& lhs, const pointer_facade<D, T, C>& rhs )
192   {
193     // 同じポインタの比較は std::less で比較する
194     return std::less<T*>()( static_cast<const D&>(lhs).get(), static_cast<const D&>(rhs).get() );
195   }
196   template<typename T, typename U, typename D1, typename D2, typename C>
197   inline bool operator< ( const pointer_facade<D1, T, C>& lhs, const pointer_facade<D2, U, C>& rhs )
198   {
199     // 異なるポインタ同士の比較は、仕方ないので < で比較する
200     return static_cast<const D1&>(lhs).get() < static_cast<const D2&>(rhs).get();
201   }
202
203 }   // namespace gintenlib
204
205
206 #endif  // #ifndef GINTENLIB_INCLUDED_POINTER_FACADE_HPP_