昔 Boost.Optional Must Go (2) - 野良C++erの雑記帳 の後半に書いた、
「boost::optional
という不満点を解決するためのクラスを作ってみました:
etude::optional_ref
http://gist.github.com/634279
使い方は boost::optional
あるいは、生ポインタと同じ、と言うべきなのかもしれません。
void f1( etude::optional_ref<int> const& ); etude::optional_ref<hoge> f2(); // 普通に参照として int i = 0; etude::optional_ref<int> p = i; *p = 42; // 引数として f1( i ); f1( boost::none ); // 関数の戻り値として if( etude::optional_ref<hoge> p = f2() ) { hoge& x = *p; // 処理 }
boost::optional
- 生ポインタからの構築が可能(ポインタの代替として使いやすいよう)
- 等号/不等号による比較が、値の比較ではなくアドレスの比較になっている(同じくポインタの代替として使いやすいよう)
- etude::make_optional_ref の存在( auto と組み合わせて使うとよし。地味に便利)
- 当然、中身が違う(各種 type_traits のメタ関数の呼び出し結果も違う*1)
生ポインタと違う点:
- デフォルト構築した時、必ず無効値に初期化される(不定値にならない)
- アドレスを取る必要がない(利便性のため、アドレスからも作れる)。 & 演算子が多重定義されていても問題なし
- 単純に delete しようとしてもコンパイルエラーになる(本質は参照なので望ましい動作)
- [] とか + とかの操作もきちんとコンパイルエラー(同じく参照なので当たり前)
- 上記をひっくるめて、無効値つきの参照(再設定可能)という意図を示しやすい
総合して、生のポインタ使うより 安全に扱えて、意図も示しやすく、かつ
boost::optional
TODO
- きっちりしたテストコード書く
- 配列に対して特殊化する
テストコード書きました。
配列に対する特殊化は面倒になったのでやめます。
そこまでいくと生ポインタと大して変わらないですし。
*1:たとえば has_trivial_destructor