检查模板参数是否继承自类

15
我想检查模板中给定的类型是否从我的项目中的基类继承而来。
它应该像以下示例所期望的那样工作:
template< class T : public CBaseClass >
  • 如果使用模板无法实现这个功能,那么还有什么其他方法可以做到呢?

请访问 https://dev59.com/lVLTa4cB1Zd3GeqPeutH 以检查类B是否派生自类A。 - Pawel Zubrycki
5个回答

14

跟随 Stroustrup 的 一个例子

template<class Test, class Base>
struct AssertSameOrDerivedFrom {
  AssertSameOrDerivedFrom() { &constraints; }
public:
  static void constraints() {
    Test *pd = 0;
    Base *pb = pd;
  }
};

template<class T>
struct YourClass {
  YourClass() {
    AssertSameOrDerivedFrom<T, CBaseClass>();
  }
};

在C++0x中,这变成了:
template<class T>
struct YourClass {
  static_assert(std::is_base_of<CBaseClass, T>::value);
};

@CrazyEddie:根据问题中的代码示例,我认为OP所说的“check”是指“assert”,而不是“如果C,则执行X,否则执行Y”。 - Fred Nurk

12

你可以使用Boost的boost::is_base_and_derived,结合BOOST_STATIC_ASSERT。如果你正在使用支持TR1或C++0x的编译器,则标准库中有那些构造的等效物(std::is_base_of和C++0x中的static_assert语句)。


很遗憾,我不能使用boost。 - Oktstrom
1
@Oktstrom:你使用的是哪个编译器?它是否支持TR1或C++0x? - Jeremiah Willcock
我正在使用Visual Studio 2010附带的编译器。 - Oktstrom
2
请检查您是否有<type_traits>头文件和其中的std::is_base_of模板。 - Jeremiah Willcock

6

如果您想要断言,请按照Nurk的方式进行。如果您想要检查,请使用boost或C++0x中的is_base_of。如果您不能使用这两者之一,请使用SFINAE:

template < typename Base, typename PotentialDerived >
struct is_base
{
  typedef char (&no)  [1];
  typedef char (&yes) [2];

  static yes check(Base*);
  static no  check(...);

  enum { value = sizeof(check(static_cast<PotentialDerived*>(0))) == sizeof(yes) };
};

2
最简单的解决方案似乎是使用std::is_base_of:
static_assert(std::is_base_of_v<CBaseClass, T>);

当然,你也可以与if constexpr结合使用:
if constexpr (std::is_base_of_v<CBaseClass, T>) {
    //
} else {
    //
}

请参阅cppreference了解更多细节:
https://en.cppreference.com/w/cpp/types/is_base_of

是的,这是现在你应该做的。大多数其他答案都已经过时了。 - Spencer

2

越短越好:

template <typename Base, typename Derived>
struct is_base {
    constexpr static bool check(Base*)   { return true; }
    constexpr static bool check(...)     { return false; }
    enum { value = check(static_cast<Derived*>(0)) };
};

例子 1:

struct A {};
struct B  : A { };

int main(void) {
    static_assert(is_base<A,B>::value, "If Error: A is not base of B");
}

例子2:
template <bool, typename T=void>
struct Use {
    static std::string info() { return "Implementation that consider that A is not base of B"; }
};

template <typename T>
struct Use<true,T>  {
    static std::string info() { return "Implementation that consider that A is the base of B"; }
};


int main(void) {
    std::cout << Use<is_base<A,B>::value>::info(); //Implementation that consider that A is the base of B
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接