使用类型特征来确保类型不能从自身派生

Using type trait to ensure a type cannot be derived from itself

我想静态地检查 class 是否是从基数 class 派生的,而不是从它自身派生的。以下是我尝试实现的示例。不幸的是,代码编译通过了(从没想过我会这么说)。

我希望第二个静态断言能够启动并看到我试图从其自身派生出 class。如果你们能帮助我更好地理解我做错了什么,我将不胜感激。我尝试在网上搜索没有成功。

#include <type_traits>

struct Base {};

template <typename T>
struct Derived : T {
  static_assert(std::is_base_of<Base, T>::value, "Type must derive from Base");
  static_assert(!(std::is_base_of<Derived, T>::value),
                "Type must not derive from Derived");
};

int main(int argc, char** argv) {
  Derived<Base> d__base; // should be OK
  Derived<Derived<Base>> d_d_base; // should be KO

  return 0;
}

Type must not derive from Derived

Derived 本身不是一个类型,它是一个模板,在 std::is_base_of<Derived, T>::value 中被解析为它所在上下文中的当前专业化,它永远不会是 T。如果你有 Derived<Derived<Base>> 那么 T 就是 Derived<Base> 而没有指定模板参数的 Derived 就是 Derived<Derived<Base>>,所以,和 T 是不一样的。

您可以添加类型特征来检查 T 是否为 Derived<something>:

template <template<class...> class F, class T>
struct is_from_template {
    static std::false_type test(...);

    template <class... U>
    static std::true_type test(const F<U...>&);

    static constexpr bool value = decltype(test(std::declval<T>()))::value;
};

现在,使用它会阻止类型 Derived<Derived<Base>>:

struct Base {};

template <typename T>
struct Derived : T {
    static_assert(std::is_base_of<Base, T>::value,
                  "Type must derive from Base");
    static_assert(!is_from_template<Derived, T>::value,
                  "Type must not derive from Derived<>");
};

int main() {
    Derived<Base> d_base;                // OK
    // Derived<Derived<Base>> d_d_base;  // error
}