move_ptr

http://lists.boost.org/MailArchives/boost/msg70905.php
(-_- )キタッ!
スケッチ程度のものかと思っていたら,ドキュメントも素晴らしいじゃないですか!
http://home.comcast.net/~jturkanis/move_ptr/
staticとdynamic2つ用意してるぅ!うぉー!!
当然staticは空のdeleterに対してはcompressが効くと!うぉー!!
dynamicは当然deleterの型が消えてると!うぉー!!

With dynamic_move_ptr, the deletion policy is applied correctly even if one or more derived-to-base conversions has occured during transfers of ownership.

ま,これはshared_ptrでもやってるから良いとして,
T[ ]による特殊化!うぉー!!
TとT[ ]では一部インターフェースが違う(operator->, operator[], operator*の有無)のね.こりゃ極めて妥当ですな.
さらにT[ ]に対して

Derived-to-base conversions with respect to the element type are disallowed.

あぁ,言われてみれば確かにそうだわな.「配列を多相的に扱うな」*1をクラスの側で実現してくれるのか.
あ,結局SFINAEによるトリッキーな実装じゃなくて無難にMOJOぽくタグ付けした実装なのね.
コンテナに入れられるっていうのはどこにも書いてないな〜.コンテナの実装によって入る/入らないが変わるからかのぉ.auto_ptr並に軽くてコンテナに突っ込めるっていうのがmove_ptrの強烈な利点のはずなんだけどな.これさえ出来たら「コンテナにポインタ入れたいんですけど」->「shared_ptr使え」->「shared_ptr重いよ」というやり取りをもう見ずに済むんだけどなぁ.
move semantics生かしたコンテナとアルゴリズムの登場を気長に待つしかないのか・・・.
#というか現状じゃ標準のコンテナには入らないな.move semantics生かせるようにコンテナの実装書き直し?うげー.

*1:参考:More Efeective C++ 項目3,標準 5.3.5 -3-

メンバ関数の選択的実装

そういえば,前々から「ポリシー等のコンパイル時決定な条件によってメンバ関数が実装されるかされないかが異なる」場合にどうするのが良いのか気になってたんですよね.ちょうど,move_ptrはTかT[ ]かでメンバ関数が実装されているかされていないかの選択になっているようなのでどうやっているんでしょうかね?と思って実装見てみる.

template< typename T, 
          typename Deleter = 
              move_ptrs::default_deleter<T> >
class static_move_ptr {
  // .....
private:
  BOOST_STATIC_CONSTANT(bool, is_array = boost::is_array<T>::value);
  // .....

public:
  // .....
  element_type& operator*() const 
  { 
    BOOST_STATIC_ASSERT(!is_array); return *ptr();
  }
  // .....
};

上のコードにおいてoperator*内のBOOST_STATIC_ASSERTの意図は「move_ptrの場合はoperator*の使用はOK.move_ptrの場合operator*を使用しようとした時点でコンパイルエラーを吐かせる.」というもの.ただし,これはクラステンプレート内のテンプレートでないメンバ関数が未使用の場合にコンパイラがそれをどう扱うかによって挙動が変わる.即ち,未使用な場合に実体化を行わないコンパイラに対して上のコードは意図通りの挙動を示すが,未使用な場合でも実体化を伴うコンパイラではmove_ptrの実体化の時点でコンパイルエラーを吐く.
う〜ん,前からこの「クラステンプレート内のテンプレートでない関数が未使用の場合,それは実体化されない」というのに依存したコードって気持ち悪いなぁって思っていたんですよねぇ.上のコードってもろにそうだし.この場合についてのシンタックスチェックのレベルは規格では確か言及されていないから厳密には実装依存のはずだしなぁ.(2004/09/15追記:どうやら標準で明記されているようであるid:Cryolite:20040915#p2)実際にはほとんど(というか全て?)の実装でtrueっていうだけだからなぁ.MC++Dでもちらっと言及しているけれど,この部分に対するツッコミってどっかでやられているのかなぁ?
この特性はpolicy-based design(←全然関係ないけれど,この前PBDって略してるのを見た)では非常に有用な特徴だから,使うなら標準で言及してくれるようにして欲しいなぁ.
以下はクラステンプレートの実体化とテンプレートでないメンバ関数の実体化の間に「時間差」が存在することを直接示すコード.VC++7.1で確認しただけだけれど,他の実装もだいたい同じはず・・・.

#include <boost/static_assert.hpp>

template<class T>
struct X{
  void f(){ BOOST_STATIC_ASSERT( false ); }
};

// こちらは定義だけでもすでにコンパイルが通らない
//struct Y{
//  void f(){ BOOST_STATIC_ASSSERT( false ); }
//};

int main()
{
  X<int> x; // インスタンスを持つのはOK.
  //x.f();  // f呼び出そうとした時点でアウト

  //Y y;

  return 0;
}

(´-`).。oO(っていうかなんでlazy evaluationする必要があるんだろう・・・)