2011-11-02 26 views
5

私は次のようなテンプレート基本クラスを持っています:テンプレート関数を基本型と派生型に限定しますか?

template<typename T, std::size_t Size> 
class VectorT 
{ 
public: 
    typedef T data_type; 
} 

といくつかの特殊な派生クラス:

template<typename T> 
class Vector2d : public VectorT<T, 2U> 
{ // some specialised functions } 

template<typename T> 
class Vector3d : public VectorT<T, 3U> 
{ // some other specialised functions } 

これらは正常です。 Howerver、私は演算子のためのいくつかの自立した関数を持っています。例:

template<typename T, size_t Size> 
VectorT<T, Size> operator*(T lhs, const VectorT<T, Size>& rhs) 
{ 
    ... 
} 

残念ながら、これらはVector2d<T>の代わりにVectorT<T, Size>を返すので、これらは派生クラスでは機能しません。

template<V> 
V operator*(typename V::data_type lhs, const V& rhs) 
{ 
    ... 
} 

これはうまくいきますが、data_typeメンバーで何かを吸うので、あいまいさにつながります。

これを回避するにはどうすればよいですか?ベクターベースまたはその派生物でしか機能しないタイプセーフな関数を書くにはどうすればよいですか?

私は再宣言し、サブクラスの演算子を再度定義する必要が回避しようとしています。

答えて

7

あなたはまだ別の基底クラス、テンプレートパラメータとは独立したものを追加し、このような塩基由来以外のタイプのための呼び出しを無効にするSFINAEを使用することができます。is_base_of< X, X >は常にtrueであることを

struct VectorBase {}; 

template< typename T, std::size_t Size > 
class VectorT : public VectorBase { ... } 

template< typename V > 
typename boost::enable_if< boost::is_base_of< VectorBase, V >, V >::type 
operator*(V lhs, V const& rhs){ ... } 

は注意、この関数は、必要以上に1つの型、つまり基本クラスVectorBaseに対して機能します。

TR1を実装するコンパイラを使用している場合は、両方の場所でstd::の代わりにboost::を使用できます。

+1

ありがとうございます、これは今晩私がSFINAEに関連する回答を与えた2回目です。私はこれが私の知識のギャップがどこにあるのかと思います!私はenable_ifがどのように動作するのか正確にはわかりませんが、これは本当にうまくいっています。ありがとうございました。 – DanDan

+0

@Kballo: 'boost ::'を 'std ::'で置き換えることに関して - 'std :: enable_if'は' boost :: enable_if_c'と厳密に同じであることに注意してください。したがって ' 'std ::'に切り替えるときには 'is_base_of'の' value 'メンバを自分で作成してください。 –

1

あなたは「素晴らしい」方法がない珍しい状況にあります。次のことが可能です。

  1. (ブーストは、おそらくそれを行うことができ、または時間をコンパイル)実行時にタイプをチェックしVectorT<>&を取り、関数内で新しいVectorTを作成し、それを返すのではなく、それを使用しています。このようにして、サブクラスをVectorTとして参照することもできます。しかし、それはあなたが演算子の代わりに関数を使用しなければなりません。
  2. K-balloが言ったことをしてください。
+1

私はオプション3が最も好きです:P –

関連する問題