2016-09-05 8 views
3

タイプ名Tを特定のタイプに制限するにはどうすればよいですか? 、他のデザインパターンがありますテンプレートを制限するイディオム/デザインパターンはありますか?

template <typename T> 
struct Worker { 
    static_assert(std::is_base_of<WorkableType, T>::value, "Needs workable type"); 
    // Do something with T 
}; 

struct WorkableType { 
    std::string toString() { return ""; } 
    int get() { return 0;} 
} 

struct WorkabelTypeA : WorkableType { 
    std::string toString() { return "A"; } 
    int get() { return 1;} 
}; 

//Similarly 
struct WorkableTypeB : WorkableType; 

をし、静的アサートとstd::is_base_ofを使用します。

template <typename T> 
struct Worker { 
    // T can only be certain type allowing specific functionality. 
    // i.e T needs to be a product of some interface, support some functions, say T::toString(), T::print(), T::get(). 
    // Do something with T 
}; 

これは私が通常やって終わるものです:
はこれを考えてみましょうへのC++の方法を制限する不正な型付きテンプレートの誤ったインスタンス化を制限しますか?

編集:C++のコンセプトが標準になると、このように思えるようです。私が推測するまで、static_assertはおそらくenable_ifよりもきれいで冗長でしょう。

+2

Google「C++のコンセプト」私はGCCが実用的な実装をしていると思う。 – Angew

+1

可能な二重化http://stackoverflow.com/q/874298/612920 – Mansuro

+1

@Angew残念ながら、それはC++ 11/14では利用できません。 – themagicalyang

答えて

2

あなたはSFINAEとテンプレート特殊化を使用することができます

// type trait that evaluates always to false to use in the primary template 
template<typename ... T> struct always_false : std::false_type { }; 

// primary template 
template<typename T, typename Enable = void> 
struct Worker { 
    static_assert(always_false<T, Enable>::value, "Needs workable type"); 
}; 

// specialisation 
template<typename T> 
struct Worker<T, std::enable_if_t<std::is_base_of<WorkableType, T>::value>> { 
... 
}; 
+0

私はOPのスニペットでゲインが表示されません。 – Jarod42

+0

@ Jarod42さらにC++があります:P – 101010

+0

@ 101010 true。私は、複数のタイプがチェックする必要がある場合、どのように拡大するのかは分かりません。私はおそらくその場合は静的なアサートに落ちるだろう。 – themagicalyang

0

それは次のように、特殊化を使用することができます。

#include<string> 

struct WorkableType { 
    std::string toString() { return ""; } 
    int get() { return 0; } 
}; 

struct A {}; 
struct B {}; 

template<typename> struct Worker; 
template<> struct Worker<A>: WorkableType {}; 

int main() { 
    Worker<A> wa; 
    // this won't compile 
    // Worker<B> wb; 
} 
+0

明示的に専門化するときは本当に助けになりません。 – themagicalyang

+0

@themagicalyangなぜですか?多分私はこの問題を誤解したでしょうか?もしそうなら、私は答えを削除するつもりです。お知らせ下さい。 – skypjack

1
あなたが特性を作成し、クラスでそれを確認することができます

、だから、の必要はありませんが継承。たとえば、次のように

template <typename T> 
using toString_t = decltype(std::declval<T>().toString()); 

template <typename T> 
using get_t = decltype(std::declval<T>().get()); 

// Use C++17, but can be done in C++11 
template <typename T> 
using has_toString = std::is_detected<toString_t, T>; 

template <typename T> 
using has_get = std::is_detected<get_t, T>; 

そして

template <typename T> 
struct Worker { 
    static_assert(has_toString<T>::value, "T should have toString"); 
    static_assert(has_get<T>::value, "T should have get"); 
}; 

Demo

+0

問題は、toStringとgetを持っているものはWorkerに行くことができますが、そうではありません。 toStringとgetを持つすべての型が実行可能なわけではありません。したがって、エラーチェックを行うには、静的なアサートを行う(またはifを有効にする)唯一の目的のために、実行可能なすべての型をダミーの基本型(WorkableType)から派生させることができます。 – themagicalyang

+0

@themagicalyang:より厳密な形質を持つかもしれません(戻り値の型はある型に変換可能であるべきです)。継承は必要ありません。 – Jarod42

1

あなたができるようにしたい正確にどのタイプを知っている場合、その特性クラスはそれを行うための簡潔な方法である:

#include <utility> 

// by default nothing is workable 
    template<class T> 
    struct is_workable : std::false_type 
    { 
    }; 

template <typename T> 
struct Worker { 
    static_assert(is_workable<T>(), "not a workable type"); 
    // T can only be certain type allowing specific functionality. 
    // i.e T needs to be a product of some interface, support some functions, say T::toString(), T::print(), T::get(). 
    // Do something with T 
}; 

// define a worker 
struct A {}; 

// make it workable 
template<> struct is_workable<A> : std::true_type {}; 

// define another worker but forget to make it workable 
struct B {}; 

int main() 
{ 
    Worker<A> wa{}; 
// Worker<B> wb{}; // compile error - not workable 
}; 
関連する問題