gpt4 book ai didi

c++ - 没有编译器 Hook ,哪些无法实现?

转载 作者:IT老高 更新时间:2023-10-28 12:57:05 28 4
gpt4 key购买 nike

C++ 11提供了标准的<type_traits>

没有编译器挂钩,它们中的哪一个是不可能实现的?

  • 注1:通过编译器挂钩,我指的是任何非标准语言功能,例如__is_builtin...
  • 注2:许多方法可以不使用钩子(Hook)来实现(请参见C++ Template Metaprogramming的第2章和/或Modern C++ Design的第2章)。
  • 注3:上一个问题中的spraff answer引用了N2984,其中某些类型特征包含以下注解:被认为需要编译器支持(感谢sehe)。
  • 最佳答案

    我已经写了一个完整的答案here-这项工作仍在进行中,因此即使我将文本剪切并粘贴到此答案中,我也会提供权威的超链接。

    另请参见libc++的Type traits intrinsic design文档。

    is_union
    is_union查询未通过任何其他方式公开的类的属性;
    在C++中,您可以使用类或结构进行的任何操作,也可以使用联合进行的操作。这个
    包括继承和获取成员指针。

    is_aggregate,is_literal_type,is_pod,is_standard_layout,has_virtual_destructor

    这些特征查询未通过任何其他方式公开的类的属性。
    本质上,结构或类是“黑匣子”。 C++语言使我们无法
    将其打开并检查其数据成员,以了解它们是否都是POD类型,或者是否
    它们中的任何一个都是private,或者该类具有任何constexpr构造函数(键is_literal_type的要求)。

    is_abstract
    is_abstract是一个有趣的案例。摘要的定义特征
    类类型是您无法获得该类型的值;所以例如
    格式不正确,以定义其参数或返回类型为抽象的函数,并且
    创建元素类型为抽象的数组类型的格式不正确。
    (奇怪的是,如果T是抽象的,那么SFINAE将适用于T[],而不适用于T()
    是否可以使用抽象的返回类型创建函数的类型;
    定义这种功能类型的实体格式不正确。)

    因此,我们可以使用以下方法非常接近is_abstract的正确实现
    这种SFINAE方法:

    template<class T, class> struct is_abstract_impl : true_type {};
    template<class T> struct is_abstract_impl<T, void_t<T[]>> : false_type {};

    template<class T> struct is_abstract : is_abstract_impl<remove_cv_t<T>, void> {};

    但是,有一个缺陷!如果 T本身是模板类,例如 vector<T>basic_ostream<char>,那么仅形成 T[]类型是可以接受的;在
    未评估的上下文,这将不会导致编译器实例化 T的主体,因此编译器将不会检测到
    数组类型 T[]。因此,在那种情况下SFINAE不会发生,我们将
    is_abstract<basic_ostream<char>>给出错误的答案。

    在未评估的上下文中进行模板实例化的唯一原因是
    现代编译器提供 __is_abstract(T)

    is_final
    is_final查询未通过任何其他方式公开的类的属性。
    具体来说,派生类的基本说明符列表不是SFINAE上下文。我们不能
    利用 enable_if_t询问“我可以创建一个从 T派生的类吗?”因为如果我们
    无法创建这样的类,这将是一个很难的错误。

    是空的
    is_empty是一个有趣的案例。我们不能只问是否是 sizeof (T) == 0,因为
    在C++中,不允许类型的大小为0;即使是一个空类也有 sizeof (T) == 1
    但是,由于“空基数”的存在,“空虚”的重要性足以使其具有类型特征
    优化:所有足够现代的编译器都会布局这两个类
    struct Derived : public T { int x; };

    struct Underived { int x; };

    同样也就是说,他们不会在 Derived中为空白留出任何空间 T子对象。这表明我们至少可以在C++ 03中测试“空”的方法
    在所有足够现代的编译器上:只需定义以上两个类并询问
    是否 sizeof (Derived) == sizeof (Underived)。不幸的是,从C++ 11开始,
    技巧不再起作用,因为 T可能是最终的,并且该类的“最终性”
    类型不会通过其他任何方式公开!因此实现 final的编译器供应商
    还必须公开类似 __is_empty(T)的内容,以使标准库受益。

    is_enum
    is_enum是另一个有趣的情况。从技术上讲,我们可以实现这种类型特征
    通过观察,如果我们的 T类型不是基本类型,即数组类型,
    指针类型,引用类型,成员指针,类或联合或函数
    类型,然后通过消除过程,它必须是枚举类型。但是,这种演绎
    如果编译器碰巧支持任何其他类型,则推理失败
    归入以上类别。因此,现代编译器公开 __is_enum(T)

    不属于以上任何类别的受支持类型的常见示例
    将是 __int128_t。 libc++实际上检测到 __int128_t的存在并包括
    归类为“整体类型”(在上面将其称为“基本类型”
    分类),但我们的简单实现则没有。

    另一个示例是 vector int,它支持Altivec vector 扩展。
    这种类型显然更“不完整”,但也“别无其他”,而且大多数
    当然不是枚举类型!

    is_trivially_constructible,is_trivially_assignable

    构造,分配和破坏的琐碎性都是
    没有通过其他任何方式公开的类。注意,有了这个基础
    我们不需要任何额外的魔术来查询默认构造的琐碎性,
    复制构造,移动任务等。代替, is_trivially_copy_constructible<T>在以下方面实现 is_trivially_constructible<T, const T&>,依此类推。

    is_trivially_destructible

    由于历史原因,此内置编译器的名称不是 __is_trivially_destructible(T)而是 __has_trivial_destructor(T)。此外,事实证明内置
    即使对于具有删除的析构函数的类类型,其计算结果也为 true!所以我们首先需要
    检查类型是否可破坏;然后,如果可以,我们可以询问内置的魔术
    那个破坏者是否确实微不足道。

    底层类型

    枚举的基本类型不会通过任何其他方式公开。你可以靠近
    通过获取 sizeof(T)并将其与所有已知类型的大小进行比较,并询问
    通过 T(-1) < T(0)获得底层类型的签名;但是这种方法仍然
    无法区分基础类型 intlong在平台上的类型
    类型具有相同的宽度(在那些类型的平台上, longlong long之间也不相同)
    类型具有相同的宽度)。

    关于c++ - 没有编译器 Hook ,哪些<type_traits>无法实现?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20181702/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com