そういえば,前々から「ポリシー等のコンパイル時決定な条件によってメンバ関数が実装されるかされないかが異なる」場合にどうするのが良いのか気になってたんですよね.ちょうど,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
う〜ん,前からこの「クラステンプレート内のテンプレートでない関数が未使用の場合,それは実体化されない」というのに依存したコードって気持ち悪いなぁって思っていたんですよねぇ.上のコードってもろにそうだし.この場合についてのシンタックスチェックのレベルは規格では確か言及されていないから厳密には実装依存のはずだしなぁ.(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する必要があるんだろう・・・)