5

次のテンプレート クラスがあるとします。

template<typename T> class Wrap { /* ... */ };

変えることはできませWrap。大事です。

から派生したクラスがあるとしWrap<T>ます。例えば、

class NewInt  : public Wrap<int>     { /* ... */ };
class MyClass : public Wrap<myclass> { /* ... */ };
class Foo     : public Wrap<Bar>     { /* ... */ };

これらのクラスも変更できません。上記のすべてのクラスはサードパーティです。彼らは私のものではありません。

次のコンパイル時間が必要ですtype_traits

template<class T>
struct is_derived_from_Wrap { 
     static const bool value = /* */;
};

私が必要なものは何?

assert(is_derived_from_Wrap<Int>::value == true);  // Indeed I need static assert
assert(is_derived_from_Wrap<MyClass>::value == true);
assert(is_derived_from_Wrap<char>::value == false);
struct X {};
assert(is_derived_from_Wrap<X>::value == false);
4

3 に答える 3

9

SFINAE を使用してこれを行うことができますが、何が起こっているのかわからない場合は魔法のようなものです...

template<typename T> class Wrap { };

struct myclass {};
struct X {};

class Int     : public Wrap<int>     { /* ... */ };
class MyClass : public Wrap<myclass> { /* ... */ };

template< typename X >
struct is_derived_from_Wrap
{
  struct true_type { char _[1]; };
  struct false_type { char _[2]; };

  template< typename U >
    static true_type test_sfinae( Wrap<U> * w);
  static false_type test_sfinae( ... );

  enum { value = sizeof( test_sfinae( (X*)(0) ) )==sizeof(true_type) };
};


#include <iostream>
#define test(X,Y) std::cout<<( #X " == " #Y )<<"  : "<<( (X)?"true":"false") <<std::endl;

int main()
{
  test(is_derived_from_Wrap <Int>::value, true);
  test(is_derived_from_Wrap <MyClass>::value, true);
  test(is_derived_from_Wrap <char>::value, false);
  test(is_derived_from_Wrap <X>::value, false);
}

これにより、期待される出力が得られます

is_derived_from_Wrap <Int>::value == true  : true
is_derived_from_Wrap <MyClass>::value == true  : true
is_derived_from_Wrap <char>::value == false  : false
is_derived_from_Wrap <X>::value == false  : false

私のコードにはいくつかの落とし穴があります。タイプが Wrap の場合も true を返します。

assert(  is_derived_from_Wrap< Wrap<char> >::value == 1 );

これは、必要に応じてもう少し SFINAE マジックを使用して修正できる可能性があります。

派生が public 派生でない場合 (つまり、 private または protected )、false を返します。

struct Evil : private Wrap<T> { };
assert( is_derived_from_Wrap<Evil>::value == 0 );

これは修正できないと思います。(しかし、私は間違っているかもしれません)。しかし、公開継承で十分だと思います。

于 2010-01-14T09:11:12.597 に答える
0

以下は、何かラップであるかどうかを決定します。

template<class T>
struct is_Wrap { static const bool value = false; };

template<typename T> 
struct is_Wrap< Wrap<T> > { static const bool value = true; };

Wrap<T>派生は Is-A の関係なので、 alsoから派生するものはすべてaWrap<T>であり、これでわかるはずです。

于 2010-01-14T08:40:34.400 に答える
0

一般に、あるクラス X が別の Y から派生しているかどうかを判断するには、かなり複雑なテンプレート メタプログラミングを行う必要があります。基本的に、次の場合、X は Y から派生します。

  1. Y は暗黙的に X に変換できます
  2. X と Y は同じ型ではありません

Andrei Alexandrescuは、彼の著書「Modern C++ Design」で、(他の多くのテンプレート トリックと共に) これを行う方法を説明しています。

問題を解決するコードは、LokiライブラリまたはuSTL実装のいずれかで見つけることができます。どちらも Alexandrescu によって作成されています。

于 2010-01-14T08:42:46.997 に答える