[C++]现代C++语言核心特性解析 Chapter 4

decltype说明符(C++11~C++17)

1 使用decltype说明符

decltype说明符可以获取对象或者表达式的类型。并且可以用于非静态成员变量。

用处

  1. 在c++11标准中,不支持对auto声明的返回类型进行推导,所以需要用decltype在函数的尾部对返回类型进行说明

    1
    2
    3
    4
    5
    6
    7
    template<class T1, class T2>
    auto sum(T1 a1, T2 a2)->decltype(a1 + a2)
    {
    return a1 + a2;
    }

    auto x4 = sum(5, 10.5);
  2. 在c++14标准中,支持对auto声明的返回类型进行推导,可以简化为

    1
    2
    3
    4
    5
    6
    7
    template<class T1, class T2>
    auto sum(T1 a1, T2 a2)
    {
    return a1 + a2;
    }

    auto x5 = sum(5, 10.5);
  3. 但是,上述代码有一点问题,如果我们期望返回一个引用,上述代码无法做到。配合decltype可以做到

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    template<class T>
    auto return_ref(T& t)->decltype(t)
    {
    return t;
    }

    int x1 = 0;
    static_assert(
    std::is_reference_v<decltype(return_ref(x1))> // 编译成功
    );

2 推导规则

decltype(e)(其中e的类型为T)的推导规则有5条。

  1. 如果e是一个未加括号的标识符表达式(结构化绑定除外)或者未加括号的类成员访问,则decltype(e)推断出的类型是e的类型T。如果并不存在这样的类型,或者e是一组重载函数,则无法进行推导。
  2. 如果e是一个函数调用或者仿函数调用,那么decltype(e)推断出的类型是其返回值的类型
  3. 如果e是一个类型为T的左值,则decltype(e)是T&。
  4. 如果e是一个类型为T的将亡值,则decltype(e)是T&&。
  5. 除去以上情况,则decltype(e)是T。

3 cv限定符的推导

  • 通常情况下,推导会同步e的cv限定符。
  • 当e是未加括号的成员变量时,父对象表达式的cv限定符会被忽略
  • 当e是加括号的成员变量时,父对象表达式的cv限定符会同步到结果

4 decltype(auto)

C++14标准中出现了decltype和auto两个关键字的结合体:decltype(auto)。它的作用简单来说,就是告诉编译器用decltype的推导表达式规则来推导auto。另外需要注意的是,decltype(auto)必须单独声明,也就是它不能结合指针、引用以及cv限定符。

有了这个用法,上述返回引用的类型可以进一步优化

1
2
3
4
5
6
7
8
9
10
template<class T>
decltype(auto) return_ref(T& t)
{
return t;
}

int x1 = 0;
static_assert(
std::is_reference_v<decltype(return_ref(x1))> // 编译成功
);

5 decltype(auto)作为非类型模板形参占位符

与auto一样,在C++17标准中decltype(auto)也能作为非类型模板形参的占位符


[C++]现代C++语言核心特性解析 Chapter 4
https://erlsrnby04.github.io/2024/10/20/C-现代C-语言核心特性解析-Chapter-4/
作者
ErlsrnBy04
发布于
2024年10月20日
许可协议