没有编译器挂钩,哪些<type_traits>无法实现?

昆布

C ++ 11提供了standard <type_traits>

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

  • 注1:所谓的编译器挂钩是指任何非标准语言功能,例如__is_builtin...
  • 注意2:它们中的很多都可以不带钩子来实现(请参阅C ++模板元编程的第2章和/或Modern C ++ Design的第2章)。
  • 注释3:在前面的问题中,spraff的答案引用了N2984,其中某些类型特征包含以下注释:据信需要编译器支持(感谢sehe)。
喹plus酮

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

另请参见libc ++有关类型特征固有设计的文档

is_union

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

is_aggregate,is_literal_type,is_pod,is_standard_layout,has_virtual_destructor

这些特征查询未通过任何其他方式公开的类的属性。本质上,结构或类是“黑匣子”。C ++语言使我们无法破解它并检查其数据成员,以查明它们是否均为POD类型,或者是否为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_tlibc ++实际上会检测到它的存在__int128_t并将其包括在“积分类型”的类别中(这在上述分类中使其成为“基本类型”),但是我们的简单实现并未实现。

另一个示例是vector int在支持Altivec矢量扩展的编译器上。这种类型显然更是“不是整数”,但也“不是其他任何东西”,并且最肯定不是枚举类型!

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之上)。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

编译器如何定义 type_traits 中的类?

来自分类Dev

为什么要使用结构实现type_traits

来自分类Dev

<type_traits>头文件中的某些实现在哪里?

来自分类Dev

<type_traits>头文件中的某些实现在哪里?

来自分类Dev

为type_traits类创建一个“求反”包装器

来自分类Dev

C ++有没有一种方法可以基于type_traits进行模板重载?

来自分类Dev

为什么必须使用'typename'和':: type'前缀/后缀来调用所有type_traits类?

来自分类Dev

std type_traits 与 Qt type_traits 冲突

来自分类Dev

标准容器的type_traits?

来自分类Dev

如何在C ++ 17中使用type_traits检测具有特定名称和签名的函数(NOT类成员)的存在

来自分类Dev

使用type_traits检查constness

来自分类Dev

致命错误:在构建clang示例时,找不到'type_traits'文件#include <type_traits>

来自分类Dev

有没有办法“告诉” IntelliSense 和编译器该类实现了接口而不实际实现它?

来自分类Dev

为什么type_traits是类而不是函数

来自分类Dev

如何将C ++概念与type_traits配合使用?

来自分类Dev

使用C ++ 11 type_traits了解Microsoft的_Is_duration

来自分类Dev

Maven嵌入器:无法解决编译器依赖性-没有可用的连接器工厂

来自分类Dev

当构造函数从实现的接口接收不同的参数类型时,Typescript编译器没有错误

来自分类Dev

为什么VS 2015编译器无法在abs()实现中优化浮点数的分支?

来自分类Dev

为什么在没有引用运算符的情况下编译器无法决定要调用哪个函数?

来自分类Dev

编译器如何实现C ++继承?

来自分类Dev

编译器实现对 ABI 的依赖

来自分类Dev

GraalVM:如何实现编译器优化?

来自分类Dev

在VS2012中编译cuda:致命错误C1083:无法打开编译器生成的文件,没有此类文件或目录

来自分类Dev

无法编译Glasgow Haskell编译器

来自分类Dev

Java编译器有哪些怪癖?

来自分类Dev

如何使用type_traits或模板功能专门化来巩固模板方法

来自分类Dev

如何不使用type_traits检查复制构造函数是否为noexcept?

来自分类Dev

严重错误:找不到'type_traits'文件-Qt 5.14 Preview Android

Related 相关文章

  1. 1

    编译器如何定义 type_traits 中的类?

  2. 2

    为什么要使用结构实现type_traits

  3. 3

    <type_traits>头文件中的某些实现在哪里?

  4. 4

    <type_traits>头文件中的某些实现在哪里?

  5. 5

    为type_traits类创建一个“求反”包装器

  6. 6

    C ++有没有一种方法可以基于type_traits进行模板重载?

  7. 7

    为什么必须使用'typename'和':: type'前缀/后缀来调用所有type_traits类?

  8. 8

    std type_traits 与 Qt type_traits 冲突

  9. 9

    标准容器的type_traits?

  10. 10

    如何在C ++ 17中使用type_traits检测具有特定名称和签名的函数(NOT类成员)的存在

  11. 11

    使用type_traits检查constness

  12. 12

    致命错误:在构建clang示例时,找不到'type_traits'文件#include <type_traits>

  13. 13

    有没有办法“告诉” IntelliSense 和编译器该类实现了接口而不实际实现它?

  14. 14

    为什么type_traits是类而不是函数

  15. 15

    如何将C ++概念与type_traits配合使用?

  16. 16

    使用C ++ 11 type_traits了解Microsoft的_Is_duration

  17. 17

    Maven嵌入器:无法解决编译器依赖性-没有可用的连接器工厂

  18. 18

    当构造函数从实现的接口接收不同的参数类型时,Typescript编译器没有错误

  19. 19

    为什么VS 2015编译器无法在abs()实现中优化浮点数的分支?

  20. 20

    为什么在没有引用运算符的情况下编译器无法决定要调用哪个函数?

  21. 21

    编译器如何实现C ++继承?

  22. 22

    编译器实现对 ABI 的依赖

  23. 23

    GraalVM:如何实现编译器优化?

  24. 24

    在VS2012中编译cuda:致命错误C1083:无法打开编译器生成的文件,没有此类文件或目录

  25. 25

    无法编译Glasgow Haskell编译器

  26. 26

    Java编译器有哪些怪癖?

  27. 27

    如何使用type_traits或模板功能专门化来巩固模板方法

  28. 28

    如何不使用type_traits检查复制构造函数是否为noexcept?

  29. 29

    严重错误:找不到'type_traits'文件-Qt 5.14 Preview Android

热门标签

归档