5

假设我们有以下模板类

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);
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 魔法来解决。

如果派生不是公共派生(即私有或受保护),它将返回 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; };

由于推导是一种 Is-A 关系,因此从Wrap<T>也派生的所有内容都是 aWrap<T>并且应该通过 this 找到。

于 2010-01-14T08:40:34.400 回答
0

在一般情况下,您需要进行一些相当复杂的模板元编程来确定一个类 X 是否派生自另一个 Y。基本上 X 派生自 Y 如果:

  1. Y 可以隐式转换为 X
  2. X 和 Y 不是同一类型

Andrei Alexandrescu在他的“现代 C++ 设计”一书中解释了如何做到这一点(以及许多其他模板技巧)。

您可以在由 Alexandrescu 编写的Loki库或uSTL实现中找到解决问题的代码。

于 2010-01-14T08:42:46.997 回答