문제

다음 템플릿 클래스가 있다고 가정합니다

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

우리 변경할 수 없습니다 Wrap. 그건 중요해.

파생 된 수업이 있습니다 Wrap<T>. 예를 들어,

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

우리 변경할 수 없습니다 이 수업도. 위의 모든 수업은 제 3 자입니다. 그들은 내 것이 아닙니다.

다음 컴파일 시간이 필요합니다 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);
도움이 되었습니까?

해결책

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

내 코드와 함께 몇 개의 gotchas가 있습니다. 유형이 랩 인 경우에도 True가 반환됩니다.

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

이것은 아마도 필요한 경우 좀 더 sfinae 마법을 사용하여 고정 될 수 있습니다.

파생이 공공 파생이 아닌 경우 거짓을 반환합니다 (즉, 개인 또는 보호)

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

나는 이것이 고칠 수 없다고 생각한다. (그러나 나는 틀릴 수 있습니다). 그러나 나는 대중의 상속이 충분하다고 생각합니다.

다른 팁

일반적인 경우 한 클래스 X가 다른 Y에서 파생되는지 확인하려면 상당히 관련된 템플릿 메타 프로 그램을 수행해야합니다. 기본적으로 x는 y에서 파생됩니다.

  1. y는 암시 적으로 x로 변환 될 수 있습니다
  2. x와 y는 같은 유형이 아닙니다

Andrei Alexandrescu 그의 저서 "Modern C ++ Design"에서이 작업을 수행하는 방법 (다른 많은 템플릿 트릭)을 설명합니다.

문제를 해결하는 코드를 찾을 수 있습니다. 로키 도서관 또는 USTL Alexandrescu가 작성한 구현.

다음은 무언가를 결정합니다 ~이다 랩 :

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

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

파생은 IS 관계이므로 Wrap<T> 또한 a Wrap<T> 이것에 의해 찾아야합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top