【问题标题】:With C++17 is it possible to detect if a struct/class has any base?使用 C++17 是否可以检测结构/类是否有任何基础?
【发布时间】:2018-02-22 01:01:19
【问题描述】:

我需要一个类型特征,如果给定类型派生自任何东西,则该特征为真,否则为假。

例如:

template<class T>
struct is_inherit
    //... logic of inheritance detection
    ;

template<class T>
void AppLogic(){
    if constexpr(is_inherit<T>::value) {
        puts("T has base");
        //...
    } else {
        puts("T doesn't have base");
        //...
    }
}

struct A {};
struct C {};
struct B: C {};

int main() {
    AppLogic<A>(); // print: T doesn't have base 
    AppLogic<B>(); // print: T has base
}

是否有可能以某种方式实现“is_inherit”特征结构?


为什么?

我正在为 Windows x64 开发手动堆栈框架构建器。根据https://docs.microsoft.com/en-us/cpp/build/return-values-cpp 文档,如果是类型:

  • 长度为 1、2、4、8、16、32 或 64 位;
  • 没有用户定义的构造函数、析构函数或复制赋值运算符;
  • 没有私有或受保护的非静态数据成员;
  • 没有引用类型的非静态数据成员;
  • 没有基类;
  • 没有虚函数;
  • 并且没有不满足这些要求的数据成员;

那么它的返回值在RAX寄存器中,否则函数 有一个我必须检测和处理的隐藏参数。

这曾经是 C++03 POD 的定义,但在 C++11 中发生了变化:

由于 C++11 标准中的定义发生了变化,因此我们不建议在此测试中使用 std::is_pod。

到目前为止,通过一些共轭特征,我可以检测该类型是否符合 C++03 POD 的定义。然而,随着 C++17 的聚合规则发生了变化,这打破了我的解决方案。

如果我能以某种方式检测类型 T 是否有任何基类,我的解决方案将再次起作用。

【问题讨论】:

  • 如果它有一个基础一般?不要以为没有“作弊”就可以做到这一点。
  • 您需要等待内省被添加到 C++ 中,或者找到编译器特定的技巧。我不认为你可以这样做。但正如 Vittorio Romeo 所建议的,这可能是一个 XY 问题。你为什么需要这个?可能有更好的方法来解决您最初的问题。
  • @Nyufu 问题是你需要这个做什么?你会如何使用它?如果我们知道您要解决的问题,我们可能会提供可行的替代方案,这实际上可能是更好的解决方案,即使您可以按照您的要求进行操作。还是这是一个哲学问题?
  • 有几件事很接​​近,std::is_trivial 或 std::is_aggregate。但是您要解决的问题到底是什么。不,不是关于确定一个类是否有任何基类的问题。但是,无论您认为解决什么问题,都需要确定一个类是否有任何基类。
  • 这不是std::is_pod 你所追求的,真的吗?只要它与任何 C 数据类型兼容,为什么基础很重要?

标签: c++ inheritance c++17 typetraits


【解决方案1】:

是的,这是可能的,至少对于聚合而言。

首先我们构造一个类模板,它可以转换为其模板参数的任何适当的基:

template<class T>
struct any_base {
    operator T() = delete;
    template<class U, class = std::enable_if_t<std::is_base_of_v<U, T>>> operator U();
};

然后我们检测模板参数T 是否可以从any_base&lt;T&gt; 类型的值聚合构造:

template<class, class = void> struct has_any_base : std::false_type {};
template<class T>
struct has_any_base<T, std::void_t<decltype(T{any_base<T>{}})>> : std::true_type {};

Example.

【讨论】:

  • 如果我有像 class E { E(B&amp;) { } }; 这样的课程,我担心 has_any_base_v 会说是真的
  • @gu1d0 哦,是的,我忘了std::is_base_of 说一个类是它自己的基础。固定以仅允许适当的基地。谢谢!
  • @gu1d0 是的,但是如果 E 有任何构造函数,那么它不是微不足道的,因此不是聚合的。 ecatmur 写了这个解决方案“至少对于聚合”有效。这将是我的 C++03 POD 检测特性的一部分,因此这个解决方案对我来说已经足够了。 template&lt;class T&gt; struct is_cpp03_pod : std::bool_constant&lt;std::is_trivial_v&lt;T&gt; &amp;&amp; std::is_aggregate_v&lt;T&gt; &amp;&amp; !has_any_base_v&lt;T&gt;&gt; {};
  • 至少对于聚合......其中第一个基类之后的所有子对象都是默认可构造的:)
  • @Nyufu struct D { B b; }; 怎么样?
【解决方案2】:

我相信检查“T 是否来自任何东西”是不可能的,至少不是以符合标准的方式。如果您使用这种技术来检查一个类型是否是 POD/平凡/聚合,那么有一些类型特征可能会对您有所帮助:

【讨论】:

  • std::is_base_of
猜你喜欢
  • 2018-09-11
  • 1970-01-01
  • 1970-01-01
  • 2012-04-11
  • 1970-01-01
  • 1970-01-01
  • 2012-07-29
  • 1970-01-01
  • 2015-11-07
相关资源
最近更新 更多