メンバ関数の選択的実装

そういえば,前々から「ポリシー等のコンパイル時決定な条件によってメンバ関数が実装されるかされないかが異なる」場合にどうするのが良いのか気になってたんですよね.ちょうど,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する必要があるんだろう・・・)