跳转至

类型声明

auto

C++11 使用 auto 来自动类型推断,这要求显示初始化,让编译器能够将变量设置为初始值的类型。auto 的推导规则如下:

  • auto 基本规则:去掉引用和 const 资格。

  • 保持引用和常量性:使用 auto&、const auto&、auto* 等。

  • 数组和指针:数组会被推导为指针

在 auto 的推导中,如果表达式本身包含自动推导的类型(如 std::vector),则这种嵌套推导在C++标准中是不允许的。但是,你可以使用模板和 decltype 来实现类似的功能。

decltype

基本规则

  • 对标识符或类成员访问表达式

decltype(x) 的类型与 x 的类型相同。如果 x 是变量,则 decltype(x) 的类型是该变量的类型。与 auto 不同的 decltype 会保留 cv 限定符和引用属性。

int i;
decltype(i) j;  // j 的类型是 int
  • 对左值表达式

如果 expr 是一个左值表达式,则 decltype(expr)T&,其中 Texpr 的类型。

int i;
decltype((i)) j = i;  // j 的类型是 int&
  • 对右值右值表达式

如果 expr 是一个右值表达式,则 decltype(expr)T,其中 Texpr 的类型。

int foo();
decltype(foo()) x = foo();  // x 的类型是 int

下面我们使用一种特殊的手段验证上述推导规则。使用一种不定义模板函数的方式,让编译器推导完类型后找不到实现报错,从而看到具体的推导类型:

#include <iostream>
#include <vector>

template<class Tp>
void f();

int main() {
    int a = 5;
    const int& b = a;
    auto c = b;          // c 是 int,auto 去掉了引用和 const
    decltype(b) d = a;   // d 是 const int&,decltype 保留了引用和 const

    std::vector<int> v;
    decltype(v[0]) e = a;  // e 是 int&,因为 v[0] 返回一个左值引用

    decltype((a)) f = a;   // f 是 int&,因为 (a) 是一个左值表达式
    decltype(a) g = a;     // g 是 int,直接使用标识符 a,decltype(a) 是 int

    return 0;
}
  • 对于标识符或类成员,decltype 获取其声明类型。
  • 对于左值表达式,decltype 会生成一个引用类型。
  • 对于右值表达式,decltype 会生成其值类型。

返回值类型后置

C++11 引入了返回值类型后置(trailing return type),这种语法通过在参数列表之后使用 -> 指定返回类型,提供了一些便利和优势。具体好处如下:

  • 当返回类型依赖于函数参数时,返回值类型后置可以更方便地表示:
template<typename T, typename U>
auto add(T t, U u) -> decltype(t + u) {
    return t + u;
}
  • lambda 表达式引入了后置返回类型的语法,使得匿名函数能够使用复杂的返回类型:
auto lambda = [](int x) -> int {
    return x + 1;
};