c++ - 检查类型是否直接派生自“启用 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++ 没有反射,子对象的存储包含父对象的存储,并且很难在一个子对象和另一个子对象之间划清界限。一些元编程必须是圆顶的,模仿类似于 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 的作用,但摆脱用户代码中的宏定义几乎是不可能的。
推荐阅读
- jsf - 如何在托管 bean 中获取 UISelectMany 自定义组件值
- java - 如何重命名在构建过程中创建的文件夹?它一直回到原来的名字
- android - 对象在应用程序相机的边缘显得模糊
- javascript - Javascript 表组产品
- c# - EFCore throw 中的单独命令/查询 DbContext 已经有一个打开的 DataReader
- java - 自 Java 9 以来,如何在运行时动态加载 JDBC 驱动程序?
- symfony4 - Easyadmin 捆绑类型的选定值:实体
- c# - 如何配置 WebpackDevServer 以使用 ASP.NET CORE 2.0 IISEXPRESS 运行应用程序
- windows - Caffe 的 Windows fork 可以用于对象检测吗?
- pytorch - 如何在 pytorch 中使用多个 GPU?