【问题标题】:How to check at compile-time inheritance using std::enable_if_t & std::is_base_of for SFINAE?如何使用 std::enable_if_t 和 std::is_base_of 为 SFINAE 检查编译时继承?
【发布时间】:2025-12-24 16:15:15
【问题描述】:

我试图在编译时将函数的模板类型限制为特定类及其子类。为了实现这一点,我使用了类型特征 std::enable_if_tstd::is_base_of,如下所示:

template <typename T = std::enable_if_t<std::is_base_of<A, T> > >

但是模板仍然编译不属于继承层次结构的类型(即int)。以下是该问题的 MCVE:

class A {
public:
  A(float a) : a(a) {}
  float a;
};
class B : public A{
public:
  B(float a) : A(a) {}
};

template <typename T = std::enable_if_t<std::is_base_of<A, T> > >
void templateFunction(T a) {

}

int main() {
  templateFunction<A>(A(1.0f)); // OK -> std::is_base_of<A, A>
  templateFunction<B>(B(1.0f)); // OK -> std::is_base_of<A, B>

  templateFunction<int>(1); // Should not compile! int is not a subclass of A -> std::is_base_of<A, int>
  return 0;
}

这在 Visual Studio 2017 下编译没有任何错误,但在我的理解中,模板函数的最后一个实例化不应该编译。 我对类型特征的使用有什么问题,还是 Visual Studios SFINAE 实现有问题?

【问题讨论】:

    标签: templates c++14 sfinae typetraits


    【解决方案1】:

    您对 enable_if 的使用有点奇怪,我会这样做:

    template <typename T>
    std::enable_if_t<std::is_base_of<A, T>::value> templateFunction(T a) {
    
    }
    

    更好的解决方案:完全忘记 SFINAE:

    template <typename T>
    void templateFunction(T a) {
      static_assert(std::is_baseOf<A,T>(), "only subclasses, please");
    }
    

    编辑、解释:将 enable_if_t 视为满足条件时成为类型的东西(默认为 void)。

    应用这个,你的函数如下:

    // true case:
    template <typename T = void>
    void templateFunction(T a) {}
    
    // false case:
    template <typename T = nonsense>
    void templateFunction(T a) {}
    

    您的调用仍然与错误情况下的模板匹配!

    现在,将其应用于我建议的代码:

    //true case:
    template <typename T>
    void templateFunction(T a) {}
    
    //false case:
    template <typename T>
    *nonsense* templateFunction(T a) {}
    

    这里函数在false的情况下根本不存在,所以会产生编译错误。

    【讨论】: