目前一部分类型特征需要编译器内建支持,如 std::is_standard_layout 目前(截止至 C++20 )需要用类似 __is_standard_layout() 的编译器扩展 intrinsic 实现。
由于 本身在不断更新,我打算写一篇长期更新的文章记录一下有什么需要内建支持的类型特征。
未来的语言级支持
另一方面,即使是能以标准代码手工实现的类型特征,手工实现往往都不是最优的:编译器在处理完类型本身的信息之后,还需要通过元编程的手段额外构造一些东西去探测,这天生地带来了额外开销。
不过假如我们有了静态反射功能,能直接利用编译器构建的类型相关信息,那么大多数需要内建扩展的类型特征都可以通过标准代码实现。而且之前的很多类型特征改用反射实现都会更有效率。
需要内建实现的类型特征
如果引入反射 TS ,则大部分可由反射 TS 中的功能实现。但也有一些例外会额外注明。
[meta.unary.cat]
is_class 或 is_union ,目前标准代码可实现两者的逻辑或。
[meta.unary.prop]
is_trivial
is_trivially_copyable
is_standard_layout
is_literal_type ( C++20 中移除)
is_empty
is_abstract
is_final
is_aggregate
is_trivially_constructible
is_trivially_assignable
is_trivially_destructible
has_virtual_destructor
has_unique_object_representations ,注意反射 TS 中的功能不足以实现,但反射 v2 中查询布局的工具能实现它。
has_strong_structural_equality (这个名称及当前定义可能很快就会改动)
[meta.rel]
is_layout_compatible
is_pointer_interconvertible_base_of
[meta.trans.other]
underlying_type
[meta.member]
is_pointer_interconvertible_with_class
is_corresponding_member ,这两者如果用反射 v2 或某些 intrinsic 实现可能比单凭反射 TS 实现更高效。
[meta.const.eval]
is_constant_evaluated ,注意反射 TS 中的功能不是用来实现它的。不过它可以由 if consteval 实现甚至在多数情况下取代。
依赖实现定义的类型特征
is_integral
make_signed
make_unsigned
这些类型特征与实现定义的扩展整数类型有关。
( is_floating_point 可能算此类,但标准并未提及扩展浮点类型)
aligned_storage
此类型特征与实现定义的最大受支持对齐和默认对齐确定方式有关。
is_empty
不能手工实现,但有些 ABI 上能写出一些忽略 final 的“实现”。
其他可能存在争议的项目
is_convertble
C++17 中(由 P0135R1 引入) , return 语句曾有可能不潜在调用结果对象的析构函数。这导致了 is_convertible 变得无法手工实现(若目标类型为不可析构的对象类型,但存在非 explicit 转换函数或可单参调用的非 explicit 构造函数)。但后来的 CWG2426 要求潜在调用,并使得之前的手工实现恢复正确。
is_nothrow_convertible
从 P0758R1 的设计来看,此类型特征应该顾及转换中目标类型对象(或目标类型引用所绑定到的临时对象)的析构,目前所有实现都遵循这一设计。
但目前标准草案的说法并没有提及析构,而这可能会导致理解分歧。目前还没有 LWG issue (应该可以确定不是编辑问题)。
不考虑析构的手工实现可能相当复杂甚至可能无法达成,与之相对地,在 C++20 requires 的帮助下考虑析构的手工实现非常简单。
is_nothrow_constructible 及其他相关的不抛出构造检测
目前标准同样是不考虑构造出来的对象(或引用绑定到的临时对象)的析构是否抛出异常。有些实现同样考虑析构函数。
后记
这东西有很大一部分对得起“应由语核内建的东西(指静态反射)交给库来实现” 这种批评。而 STL 容器之类的大抵并非如此。应该就是这些了。