2011-12-15 4 views
5

私はテンプレート関数を持っており、コンパイル時に特定のクラスのサブタイプまたはスーパータイプでインスタンス化されないようにしたいと考えています。テンプレートが特定のタイプのものであるというコンパイル時間アサーションを作成するにはどうすればよいですか?

これに違反すると、C++コンパイラエラーが発生することはありますか?

class base { 
}; 
class derived : public base { 
}; 
class lowest : public derived { 
}; 

template <typename T> 
bool isCorrect(const T& obj) { 
    typedef foo<T> D; 
    foo<T> *def = foo<T>::find(); 
    return (def && def->getAnswer(object)); 
} 

私だけにisCorrectがクラスderivedはなく、baselowestのために利用できるようにしたいです。注目すべき他の多くの最下位クラスと、除外される基本クラスの文字列と、受け入れ可能な代替派生クラスが存在することに注意してください。

明示的に指定する派生クラスのみにテンプレートを適用する方法はありますか?

+0

可能重複[テンプレート制約C++](http://stackoverflow.com/questions/122316/template-constraints-c ) –

+0

具体的には、これは役に立つかもしれません:http://www.boost.org/doc/libs/1_48_0/libs/concept_check/concept_check.htm –

+0

あなたは単に過負荷を書きませんか? – GManNickG

答えて

4

これは私が知っている1つの手法です。

まず、別のテンプレートクラスpolicy_enforcerを作成します。それ定義せずに、このクラスを宣言し、またもを定義しているderivedのためにそれの専門を提供します。

template<typename T> struct policy_enforcer; 
template<> struct policy_enforcer<derived> { }; 

次に、関数内であなたは、ロックダウンしたい表現sizeof(policy_enforcer<T>)が含まれます。不完全な型のsizeofはコンパイルエラーであるため、コードがコンパイルされません。using baseusing derivedusing lowest:ライブコードを更新しました

+0

少し鈍いですが、うまくいくでしょう。うまくいけば、あまり知られていない方法を誰かが投稿してくれることを願っています。 – WilliamKF

9

型形質、具体的にはis_base_of

#include <type_traits> 

template <typename T> 
bool isCorrect(const T& obj) { 
    static bool const is_base = std::is_base_of<base, T>::value; 
    static bool const derives = std::is_base_of<derived, T>::value; 
    // specify allowed types here 
    static bool const is_derived = std::is_same<T, derived>::value; 
    // --- 
    static_assert((!is_base && !derives) || is_derived, "wrong argument type"); 

    typedef foo<T> D; 
    foo<T> *def = foo<T>::find(); 
    return (def && def->getAnswer(object)); 
} 

これはC++ 11固有のものですが、Boost.TypeTraitsでも同じ動作が得られることに注意してください。

1

テンプレートの特殊化を使用できます。

isCorrectは、作業できるタイプにのみ実装できます。

たとえば、falseを返すダミーメソッドを実装するか、またはisCorrectをまったく実装しない場合は、他の型についてはコンパイルされません。

#include <iostream> 

using namespace std; 

class base { 
}; 
class derived : public base { 
}; 
class lowest : public derived { 
}; 

// using this it will fail if you try to pass anything 
// else than `derived` 
// template <typename T> 
//  bool isCorrect(const T& obj); 

template <typename T> 
bool isCorrect(const T& obj) { 
    cout << __PRETTY_FUNCTION__ << endl; 
    return false; 
} 

template <> 
bool isCorrect<derived>(const derived& obj) { 
    cout << __PRETTY_FUNCTION__ << endl; 
    return true; 
// typedef foo<derived> D; 
// foo<derived> *def = foo<derived>::find(); 
// return (def && def->getAnswer(object)); 
} 

試験:

int main() 
{ 
    base b; 
    derived d; 
    lowest l; 

    cout << isCorrect(b) << endl; 
    cout << isCorrect(d) << endl; 
    cout << isCorrect(l) << endl; 
} 

出力:

bool isCorrect(const T&) [with T = base] 
0 
bool isCorrect(const T&) [with T = derived] 
1 
bool isCorrect(const T&) [with T = lowest] 
0 
+0

'__func__'は' __FUNCTION__'、 '__PRETTY_FUNCTION__'などのC++ 11に相当します。 – Xeo

+0

これは等価ではありません....まず、C++ 11の要件はありません。' __PRETTY_FUNCTION__ '、それは質問の一部ではなかった、情報のためのbtwありがとう:)? '__func__'や' __FUNCTION__'を使うと 'isCorrect'や' isCorrect 'しか得られないので、非特化バージョンと呼ばれる他の型は見えません.... – stefanB

+0

何も間違っていません、 C++ 11が現在の標準であるためです。他のもの( '__FUNCTION__'、' __PRETTY_FUNCTION__'など)は、標準ではなく、ほとんどの場合移植性がありません。 :) – Xeo

関連する問題