C++标准模板(STL)- 类型支持 (杂项变换, 确定类型组的共用引用类型,std::common_reference)

类型特性

类型特性定义一个编译时基于模板的结构,以查询或修改类型的属性。

试图特化定义于 <type_traits> 头文件的模板导致未定义行为,除了 std::common_type 可依照其所描述特化。

定义于<type_traits>头文件的模板可以用不完整类型实例化,除非另外有指定,尽管通常禁止以不完整类型实例化标准库模板。

杂项变换

确定类型组的共用引用类型

复制代码
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 ),则:
    • 若 T1 和 T2 都是引用类型,而 T1 和 T2 的简单共用引用类型 S 存在,则成员类型 type 指名 S ;
    • 否则,若 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> 存在,且 std::common_reference_t<std::common_reference_t<T1, T2>, R...> 存在,则成员类型 type 指代它。所有其他情况下,无成员类型 type 。

二个引用类型 T1 和 T2 的简单共用引用类型定义如下:

  • 若 T1 为 cv1 X & 而 T2 为 cv2 Y & (即都是左值引用):则其简单共用引用类型为 decltype(false? std::declval<cv12 X &>() : std::declval<cv12 Y &>()) ,其中 cv12 为 cv1 与 cv2 的联合,若该类型存在且为引用类型;
  • 若 T1 a与 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 。
  • 否则,无简单共用引用类型。

成员类型

|--------|-------------------|
| 名称 | 定义 |
| type | 所有 T... 的共用引用类型 |

辅助类型

|---------------------------------------------------------------------------------------------------------------------------------|---|---|
| template< class... T > using common_reference_t = typename 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<T, std::decay_t<T>> 与 std::is_same<U, std::decay_t<U>> 皆为 true ,且它们至少有一个依赖于程序定义类型,则程序可以在前二个形参 T 和 U 上特化 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 自身。以违背这些规则的方式添加特化的程序拥有未定义行为。

调用示例

复制代码
#include <type_traits>
#include <typeinfo>
#include <iostream>

namespace std
{
template <class... Ts>
struct common_reference;

template <class T, class U>
struct common_reference<T, U>
{
    using type = decltype(std::declval<T>() = std::declval<U>());
};

template <class T, class U, class... Args>
struct common_reference<T, U, Args...>
{
    using type = common_reference<typename common_reference<T, U>::type, Args...>;
};

template <class T, class U>
using common_reference_t = typename common_reference<T, U>::type;
} // namespace std

int main()
{
    std::cout << "std::common_reference < int&, int&& >         :     "
              <<  typeid(std::common_reference < int&, int&& >).name() << std::endl;
    std::cout << "std::common_reference_t < int&, int&& >       :     "
              <<  typeid(std::common_reference_t < int&, int&& >).name() << std::endl;
    std::cout << "-----------------------------------------------" << std::endl;
    std::cout << std::endl;

    std::cout << "std::common_reference<int&, double&>          :     "
              <<  typeid(std::common_reference<int&, double&>).name() << std::endl;
    std::cout << "std::common_reference_t<int&, double&>        :     "
              <<  typeid(std::common_reference_t<int&, double&>).name() << std::endl;
    std::cout << "-----------------------------------------------" << std::endl;
    std::cout << std::endl;

    std::cout << "std::common_reference<double&, double&&>      :     "
              <<  typeid(std::common_reference < double &, double && >).name() << std::endl;
    std::cout << "std::common_reference_t<double&, double&&>    :     "
              <<  typeid(std::common_reference_t < double&, double && >).name() << std::endl;
    std::cout << "-----------------------------------------------" << std::endl;
    std::cout << std::endl;

    std::cout << "std::common_reference<bool&, bool&&>          :     "
              <<  typeid(std::common_reference < bool &, bool && >).name() << std::endl;
    std::cout << "std::common_reference_t<bool&, bool&&>        :     "
              <<  typeid(std::common_reference_t < bool&, bool && >).name() << std::endl;
    std::cout << "-----------------------------------------------" << std::endl;
    std::cout << std::endl;

    std::cout << "std::common_reference<bool&, const bool&&>    :     "
              <<  typeid(std::common_reference < bool &, const bool && >).name() << std::endl;
    std::cout << "std::common_reference_t<bool&, const bool&&>  :     "
              <<  typeid(std::common_reference_t < bool&, const bool && >).name() << std::endl;
    std::cout << "-----------------------------------------------" << std::endl;
    std::cout << std::endl;

    std::cout << "std::common_reference<char&, char&&>          :     "
              <<  typeid(std::common_reference < char &, char && >).name() << std::endl;
    std::cout << "std::common_reference_t<char&, char&&>        :     "
              <<  typeid(std::common_reference_t < char&, char && >).name() << std::endl;
    std::cout << "-----------------------------------------------" << std::endl;
    std::cout << std::endl;

    return 0;
}

输出

复制代码
std::common_reference < int&, int&& >         :     St16common_referenceIJRiOiEE
std::common_reference_t < int&, int&& >       :     i
-----------------------------------------------

std::common_reference<int&, double&>          :     St16common_referenceIJRiRdEE
std::common_reference_t<int&, double&>        :     i
-----------------------------------------------

std::common_reference<double&, double&&>      :     St16common_referenceIJRdOdEE
std::common_reference_t<double&, double&&>    :     d
-----------------------------------------------

std::common_reference<bool&, bool&&>          :     St16common_referenceIJRbObEE
std::common_reference_t<bool&, bool&&>        :     b
-----------------------------------------------

std::common_reference<bool&, const bool&&>    :     St16common_referenceIJRbOKbEE
std::common_reference_t<bool&, const bool&&>  :     b
-----------------------------------------------

std::common_reference<char&, char&&>          :     St16common_referenceIJRcOcEE
std::common_reference_t<char&, char&&>        :     c
-----------------------------------------------
相关推荐
wo_jack12 分钟前
C++ 入门笔记(十六):第16课 vector 模拟实现十问十答 —— 从三指针到迭代器失效
c++·后端·面试·stl·vector
D e re k ZH41 分钟前
C++ 标准库算法全景指南
数据结构·c++·算法
冻柠檬飞冰走茶2 小时前
字母移动游戏题解:贪心求最长可保留连续子串(附 C 实现)
c语言·开发语言·数据结构·算法·动态规划
FRing032 小时前
vue2干货总结7(自定义指令、插槽、单页应用程序、路由的使用(VueRouter))
开发语言·前端·vue.js·vue2
雪落漂泊2 小时前
C++算法 二分查找篇(上)
开发语言·c++·算法
波力海苔夹心脆6753 小时前
C# WPF 资源字典详解:ResourceDictionary、MergedDictionaries 与自定义控件案例
开发语言·c#·wpf·入门教程·resource·资源字典
不会算法的笨小孩3 小时前
异常的使用以及会出现的问题
开发语言·c++·c++11·异常
Hhy_11075 小时前
《C++深度解构06》手撕 string —— 从底层内存管理到深浅拷贝彻底吃透
c语言·开发语言·c++·学习·visual studio
starzy19906 小时前
深入理解Scala函数定义:从方法到函数的类型跨越
开发语言·scala
starzy19906 小时前
深入理解Scala递归函数:从栈溢出到尾调用优化
开发语言·scala