2012-08-29 10 views
6

クラスBがstd :: vectorから派生しているかどうかをコンパイル時にテストする方法は?クラスBがクラスのテンプレートファミリから派生しているかどうかをテストする方法

template<class A> 
struct is_derived_from_vector { 
    static const bool value = ????; 
}; 

クラスBがテンプレートファミリから派生しているかどうかをコンパイル時にテストするにはどうすればよいですか?

template<class A, template<class> class Family> 
struct is_derived_from_template { 
    static const bool value = ????; 
}; 

使用:

template<class T> struct X {}; 

struct A : X<int> {} 
struct B : std::vector<char> {} 
struct D : X<D> {} 

int main() { 
    std::cout << is_derived_from_template<A, X>::value << std::endl; // true 
    std::cout << is_derived_from_template<D, X>::value << std::endl; // true 
    std::cout << is_derived_from_vector<A>::value << std::endl; // false 
    std::cout << is_derived_from_vector<B>::value << std::endl; // true 
} 
+4

(私はC++ 11がここに助けることができることを確認していないが)、それはあなたが唯一のC++ 03やC++ 11のソリューションを必要とするかどうか、それが明示的にすることが重要であることは良いです。そして、スマートな発言として、標準コンテナから継承するべきではないということを考えると、元の特性は単純です: 'false':P –

+0

C++ 03。私はmsvc 2010コンパイラを使用します。したがって、私は 'decltype'を使うことに同意します。 'std :: vector'は例えばonyです。 C++ 03のソリューションがわからない場合は、C++ 11のソリューションも歓迎します。 –

答えて

12

はこれを試してみてください:

#include <type_traits> 

template <typename T, template <typename> class Tmpl> // #1 see note 
struct is_derived 
{ 
    typedef char yes[1]; 
    typedef char no[2]; 

    static no & test(...); 

    template <typename U> 
    static yes & test(Tmpl<U> const &); 

    static bool const value = sizeof(test(std::declval<T>())) == sizeof(yes); 
}; 

使用方法:行でが#1をマークし、あなたは可能性:注

#include <iostream> 

template<class T> struct X {}; 

struct A : X<int> {}; 

int main() 
{ 
    std::cout << is_derived<A, X>::value << std::endl; 
    std::cout << is_derived<int, X>::value << std::endl; 
} 

また、あなたの形質はwritintによって任意の少なくとも一つを持っているテンプレートが、おそらくより多くの型の引数を受け入れます

私はクラスは、ベクターに由来する場合のように(知る必要が同じような状況があった
template <typename, typename...> class Tmpl 
+0

'template class Tmpl'を使用し、テスト関数にパラメータパックを使用する場合は、1つだけでなく、任意の数の引数を持つテンプレートも扱うことができます。 –

+1

このアプローチの問題は、単一の引数を持つテンプレートに対してのみ機能することです。 'std :: vector'の*普通の* 2つの引数を取るように補足しても、実装は余分なテンプレートパラメータを(それらのパラメータのデフォルト値を提供する限り)追加することができます。したがって、100%移植可能ではありません –

+1

@DavidRodríguez-dribeas:ええ、それをバリデーションにしてください... –

1

)-クラス。残念ながら、私のプロジェクトではC++ - 11または可変マクロは使用できません。だから私のソリューションは、最後にいくつかのgoogletestコードでKerrek's answerの混合物と、このarticleた:

#include <vector> 

template <typename T> 
class is_derived_from_vector 
{ 
    typedef char Yes_t[1]; 
    typedef char No_t[2]; 

    static No_t& test(const void* const); 

    template <typename U> 
    static Yes_t& test(const std::vector<U>* const); 

public: 
    static const bool value = ((sizeof(test(static_cast<T*>(0)))) == (sizeof(Yes_t))); 
}; 

template<class T> struct X {}; 
struct A : X<int> {}; 
struct B : std::vector<char> {}; 

TEST(Example, IsDerivedFrom) 
{ 
    EXPECT_FALSE(is_derived_from_vector<A>::value); 
    EXPECT_TRUE(is_derived_from_vector<B>::value); 
} 

私はC++の使用せずに定義することはできないと思う任意のテンプレートのための共通のソリューション - 11以上。

0

私はずっと前にこの問題に対する解決策を探していたと

現代C++の設計と相談した後:適用ジェネリックプログラミングおよびデザインパターン

私は次のように構築することができたましたコメントに記載されているものと多かれ少なかれ類似しています。テンプレートメタプログラミングで

#include <iostream> 
#include <type_traits> 
#include <utility> 

template <typename T, template <typename...> class U> 
struct is_derived 
{ 
private: 
    template <typename...Ts> 
    static constexpr std::true_type check(const U<Ts...>&); 
    static constexpr std::false_type check(...); 


    template <typename> 
    struct is_same 
    { 
     static constexpr bool value = false; 
    }; 

    template <typename...Ts> 
    struct is_same <U<Ts...>> 
    { 
     static constexpr bool value = true; 
    }; 

    public: 
    static constexpr bool value = 
     std::is_same<decltype(check(std::declval<T>())), 
        std::true_type>::value && 
     !is_same<T>::value; 
}; 

template <typename, typename> 
struct X 
{ 
}; 

template <typename T> 
struct Y : X <T, int> 
{ 
}; 


int main(int argc, char **argv) { 

    std::cout << std::boolalpha << is_derived<Y<int>, X>::value << std::endl; 
    std::cout << std::boolalpha << is_derived<X<int,int>, X>::value << std::endl; 
    std::cout << std::boolalpha << is_derived<int, X>::value << std::endl; 

    return 0; 
} 
関連する問題