std::common_reference
定义于头文件 <type_traits> |
||
template< class... T > struct common_reference; |
(C++20 起) | |
确定类型 `T...` 的公共引用类型,即 `T...` 中的所有类型都可以转换或绑定到的类型。如果存在这样的类型(根据以下规则确定),则成员 `type` 命名该类型。否则,不存在成员 `type`。如果 `T...` 中的任何类型是不完整类型(除了可能带 cv 限定符的 `void`),则行为是未定义的。
当给定引用类型时,`common_reference` 尝试查找一个引用类型,所有提供的引用类型都可以绑定到该引用类型,但如果找不到这样的引用类型,则可能返回非引用类型。
- 如果 sizeof...(T) 为零,则没有成员 `type`。
- 如果 sizeof...(T) 为一(即 `T...` 只包含一种类型 `T0`),则成员 `type` 命名与 T0 相同的类型。
- 如果 sizeof...(T) 为二(即 `T...` 包含两种类型 `T1` 和 `T2`)
- 令类型 `S` 为 `T1` 和 `T2` 的*简单公共引用类型*(如下定义)。如果满足以下所有条件,成员类型 `type` 命名 `S`
- `T1` 和 `T2` 都是引用类型
- `S` 格式良好
- 令类型 `S` 为 `T1` 和 `T2` 的*简单公共引用类型*(如下定义)。如果满足以下所有条件,成员类型 `type` 命名 `S`
|
(C++23 起) |
- 否则,如果 std::basic_common_reference<std::remove_cvref_t<T1>, std::remove_cvref_t<T2>, T1Q, T2Q>::type 存在,其中 `TiQ` 是一个一元别名模板,使得 TiQ<U> 是 `U` 加上 `Ti` 的 cv 限定符和引用限定符,则成员类型 `type` 命名该类型;
- 否则,如果 decltype(false? val<T1>() : val<T2>()),其中 `val` 是函数模板 template<class T> T val();,是一个有效类型,则成员类型 `type` 命名该类型;
- 否则,如果 std::common_type_t<T1, T2> 是一个有效类型,则成员类型 `type` 命名该类型;
- 否则,不存在成员 `type`。
- 如果 sizeof...(T) 大于二(即 `T...` 由类型 `T1, T2, R...` 组成),那么如果 std::common_reference_t<T1, T2> 存在,则成员 `type` 表示 std::common_reference_t<std::common_reference_t<T1, T2>, R...>,如果这样的类型存在。在所有其他情况下,不存在成员 `type`。
两个引用类型 `T1` 和 `T2` 的*简单公共引用类型*定义如下:
- 如果 `T1` 是 `cv1 X&` 且 `T2` 是 `cv2 Y&`(即,两者都是左值引用类型):它们的简单公共引用类型是 decltype(false? std::declval<cv12 X&>() : std::declval<cv12 Y&>()),其中 *cv12* 是 *cv1* 和 *cv2* 的并集,如果该类型存在且是引用类型;
- 如果 `T1` 和 `T2` 都是右值引用类型:如果 `T1&` 和 `T2&` 的简单公共引用类型(根据上一条确定)存在,则令 `C` 表示该类型对应的右值引用类型。如果 std::is_convertible_v<T1, C> 和 std::is_convertible_v<T2, C> 都为 true,则 `T1` 和 `T2` 的简单公共引用类型是 `C`;
- 否则,两种类型之一必须是左值引用类型 `A&`,另一种必须是右值引用类型 `B&&`(`A` 和 `B` 可能带 cv 限定符)。令 `D` 表示 A& 和 B const& 的简单公共引用类型(如果有)。如果 D 存在且 std::is_convertible_v<B&&, D> 为 true,则简单公共引用类型是 `D`;
- 否则,没有简单公共引用类型。
请参阅 条件运算符,了解像上面使用的表达式 false ? X : Y 类型的定义。
目录 |
[编辑] 成员类型
名称 | 定义 |
类型
|
所有 `T...` 的公共引用类型 |
[编辑] 辅助类型
template< class... T > using common_reference_t = std::common_reference<T...>::type; |
||
template< class T, class U, template<class> class TQual, template<class> class UQual > struct basic_common_reference {}; |
||
类模板 `basic_common_reference` 是一个定制点,允许用户影响 `common_reference` 对于用户定义类型(通常是代理引用)的结果。主模板是空的。
[编辑] 特化
如果 std::is_same_v<T, std::decay_t<T>> 和 std::is_same_v<U, std::decay_t<U>> 都为 true,并且其中至少一个依赖于程序定义类型,则程序可以针对前两个参数 `T` 和 `U` 对 std::basic_common_reference<T, U, TQual, UQual> 进行特化。
如果这样的特化具有名为 `type` 的成员,则它必须是一个公共且明确的成员,命名一种类型,使得 TQual<T> 和 UQual<U> 都可以转换为该类型。此外,std::basic_common_reference<T, U, TQual, UQual>::type 和 std::basic_common_reference<U, T, UQual, TQual>::type 必须表示相同的类型。
程序不得特化 `basic_common_reference` 的第三或第四个参数,也不得特化 `common_reference` 本身。违反这些规则添加特化的程序具有未定义行为。
标准库提供了 `basic_common_reference` 的以下特化:
确定两个 pair 的公共引用类型(类模板特化) | |
确定 tuple 和 tuple-like 类型的通用引用类型(类模板特化) | |
确定 `reference_wrapper` 和非 `reference_wrapper` 的公共引用类型 (类模板特化) |
[编辑] 注意
特性测试宏 | 值 | 标准 | 特性 |
---|---|---|---|
__cpp_lib_common_reference |
202302L |
(C++23) | 将 std::reference_wrapper 的 std::common_reference_t 设为引用类型 |
[编辑] 示例
#include <concepts> #include <type_traits> static_assert( std::same_as< int&, std::common_reference_t< std::add_lvalue_reference_t<int>, std::add_lvalue_reference_t<int>&, std::add_lvalue_reference_t<int>&&, std::add_lvalue_reference_t<int>const, std::add_lvalue_reference_t<int>const& > > ); int main() {}
[编辑] 另请参阅
(C++11) |
确定一组类型的公共类型 (类模板) |
(C++20) |
指定两种类型共享一个共同的引用类型 (概念) |