如何优雅地检查模板类型是否来自C 11中的特定基类

How to elegantly check if the template type is derived from the specific base class in C++11?

本文关键字:基类 检查 何优雅 是否 类型      更新时间:2023-10-16

我有一个模板类Context。我想限制用户使用从特定类Base派生的指定类型(Stratege1,而不是Stratege2(。

class Base {
public: 
    virtual void run() = 0;
}; 
class Stratege1 : public Base {
public:
    virtual void run() {
        printf("Stratege1 n");
    }
}; 
class Stratege2 {
public:
    virtual void run() {
        printf("Stratege2 n"); 
    }
}; 
template <typename T> class Context {
public:
    void run() { 
        t.run();
    }; 
private:
    T t;
};

如果用户想这样调用,则可以:

Context<Stratege1> context;
context.run();

但是,我不希望用户使用(避免出乎意料的潜在运行时问题(

Context<Stratege2> context;
context.run();

因为Stratege2不是从Base类得出的。是否有任何优雅的方法可以限制编译期间的概念?

感谢您的建议。

自C 11以来,您可以static_assert某物,这意味着当编译时检查失败时会出现一个不错的编译错误:

#include <type_traits> // is_base_of
template <typename T>
class Context {
    static_assert(std::is_base_of<Base, T>::value,
        "T must be a derived class of Base in Context<T>.");
public:
    void run() { 
        t.run();
    }; 
private:
    T t;
};

例如:

Context<NotBase> c2;
error: static_assert failed "T must be a derived class of Base in Context<T>."
    -> static_assert(std::is_base_of<Base, T>::value,
note: in instantiation of template class 'Context<NotBase>' requested here
    -> Context<NotBase> c2;

完整程序演示

使用std::enable_if_t(相当于std::enable_if<B,T>::type(和std::is_base_of

#include <type_traits>
template <typename T,
    typename = std::enable_if_t<std::is_base_of<Base, T>::value> >
class Context {
public:
    void run() { 
        t.run();
    }; 
private:
    T t;
};

是否有任何优雅的方式来限制编译期间的概念?

另一个可能的解决方案是通过部分专业化:仅当T从base

派生时,第二个模板paramenter是true
template <typename T, bool = std::is_base_of<Base, T>::value>
class Context;
template <typename T>
class Context<T, true>
 {
   private:
      T t;
   public:
      void run () { t.run(); }; 
 };

所以你有

Context<Stratege1>  cs1;    // compile
// Context<Stratege2>  cs2; // compilation error

不幸的是,您可以劫持Context阐明第二个参数

Context<Stratege2, true> cs2; // compile