首页 > 解决方案 > 检查类型是否直接派生自“启用 if”上下文中的另一种类型(是其子类型)

问题描述

C++ 有is_base_of<Base,Derived>. 但是,这也包括“祖父母”类型。

有没有办法获得is_child_of<Parent,Child>功能?目的是在 SFINAE 上下文中使用类型作为哨兵“接口”标记,而不受可能添加或不添加到父类型的哨兵的影响。

也就是说,以下输出预计为“真,假”。(输出is_base_of为“真,真”。)

#include <iostream>
#include <type_traits>

class A {};

class B : A {};

class C : B {};

int main() 
{
    std::cout << std::boolalpha;
    std::cout << "a2b: " << std::is_child_of<A, B>::value << '\n';
    std::cout << "a2c: " << std::is_child_of<A, C>::value << '\n';
}

标签: c++inheritancesfinaeenable-ifsubtype

解决方案


C++ 没有反射,子对象的存储包含父对象的存储,并且很难在一个子对象和另一个子对象之间划清界限。一些元编程必须是圆顶的,模仿类似于 Qt 或 MFC\WFC 的库

#include <iostream>
#include <type_traits> 

#define DECLARE_CLASS(Name,  ParentName)  using Parent = ParentName;
#define PARENT_CLASS(Name) Name::Parent

class LibBase {
public:
     DECLARE_CLASS(LibBase,  void)
};

class A : public LibBase {
public:
    DECLARE_CLASS(A,  LibBase)
};

class B : public A {
public:
    DECLARE_CLASS(B,  A)
};

int main()
{
    std::cout << std::boolalpha;
    std::cout << std::is_same<PARENT_CLASS(B), A>::value << std::endl;
    std::cout << std::is_same<PARENT_CLASS(B), LibBase>::value << std::endl;
}

显然,这种简单的方法有一个陷阱,如果没有使用我们的宏定义类,我们不会得到错误。而且它只是静态的,

第一个问题可以通过声明创建一个“特征”嵌套类来解决,它的名称基于传递给 DECLARE_OBJECT 的类名。这将使 PARENT_CLASS(Name) 的结果唯一,例如

#define DECLARE_CLASS(Name,  ParentName)  struct TraitsOf##Name { \
    using Parent = ParentName; \
};

#define PARENT_CLASS(Name) Name::TraitsOf##Name::Parent

第二个问题可以通过在宏定义中创建自己的 RTTI 函数来解决

遗憾is_child_of<LibBase, A>::value的是,这种形式无法实现,因为宏替换发生在模板替换之前。也许可以使用一些静态注册方法来为类赋予独特的特征,等待 BOOST_TYPEOF 的作用,但摆脱用户代码中的宏定义几乎是不可能的。


推荐阅读