HOME
BLOG
auto关键字进阶
May 22 2023

auto💓

本篇开启Cpp进阶系列

==auto在编译期间自动推导出变量的类型。==

==auto 仅仅是一个占位符,在编译器期间它会被真正的类型所替代。==

auto在版本迭代中技巧太多,下面简单总结。注意auto是不能用在定义数组的,下面我说的都是版本证实的

在C++11中,auto关键字不能用于定义数组。例如:

c++复制代码auto arr[] = {1, 2, 3}; // 编译错误

上面的示例中,auto关键字用于定义数组,但是编译会失败,因为编译器无法推断出数组的类型。

如果要使用auto关键字定义类型,则需要将其用于定义数组的元素,并使用大括号括起来初始化数组。例如:

c++复制代码auto x = 1; // 推导为int类型
auto arr = {1, 2, 3}; // 推导为std::initializer_list<int>
eg:
int main() {
    auto arr = {1, 2, 3};
    for(auto x:arr)
    {
        cout<<x<<endl;
    }
    getchar();
    return 0;
}

在上面的示例中,auto关键字用于定义变量x和数组arr的元素类型,并且使用大括号初始化arr数组,此时编译器可以自动推导出arr数组的类型为std::initializer_list<int>

如果需要使用auto关键字定义数组,可以使用C++17中新增的auto作为数组的元素类型来实现。例如:

c++复制代码auto arr = std::array{1, 2, 3}; // 推导为std::array<int, 3>

在上面的示例中,使用std::arrayauto关键字定义了一个数组arr,此时编译器可以自动推导出arr数组的类型为std::array<int, 3>

C++11

C++11 中引入了一个新的关键字 auto , 用于自动型别推导. 同时引入了一个新的写法.

auto func(T parameters) -> type;

把函数返回类型写在后面, 这叫做 trailing return type. 这个写法等价于把 type 放在前面的通常函数, 比如

type func(T parameters);

所以说 auto 关键字只是一个占位符, 不过配合上同为 C++11 引入的 decltype 关键字, 就可以进行类型推导. 比如下面这个模板函数

template <typename U, typename V>
auto add(U a, V b) -> decltype(a + b);
// add(float, double) 返回 double
// add(float, int) 返回 float
// 诸如此类

这样可以通过 a + b 的型别推断出 add 函数的返回类型. 这样的话, 返回的型别就可以利用函数参数的型别所决定了.

C++14

新的占位符 auto

C++14 允许你在函数定义的时候, 使用真正的 auto , 如果在一个函数定义的时候用上 auto , 那他就会按照下面这个方式推断.

auto func(T parameters){
    return something;
}

这个 auto 推导的结果就相当于

auto value = something;

之中的 auto 所推导的结果. 类似地, auto & , auto && , const auto , const auto & 等关键字也都是这个原理.

这些关键字使用上是有区别的, 比如 auto & 只能返回左值引用, 而 auto && 既能返回左值引用, 又能返回右值引用. auto 只能返回一个型别. 等等.

这样子的写法只能在函数定义中使用, 因为必须同时提供返回值才能完成推导.

老的占位符 auto

C++14 为 C++11 中这种写法

auto func(T parameter) -> decltype(something) // decltype() 中就是返回值
{
    return something;
}

留了个简化的写法:

decltype(auto) func(T parameter)
{
    return something;
}

同样我们需要给出函数的 definition, 而不只是 declaration.

这就是常用的 decltype(auto) 的含义了.

decltype 的推导规则和 auto , auto & , auto && , const auto , const auto &都不一样. 它既可以返回类型, 又可以返回左右值引用, 还会保留 const 语义, 挺不一样的.

用在 lambda 中

定义一个典型的 lambda 实际上需要

  1. 捕获 [],
  2. 函数参数 (),
  3. 返回类型 type,
  4. 函数定义 {}.
auto f = []() -> type {};

这里我们省略了一些关键字, 比如 mutable , noexcept 等. C++17 中还可以用 constexpr 等关键字.

当然这个 -> type 也可以不写. 不写就意味着被 C++14 中的 -> auto 占位了. 包括 C++11 也是这样的, 尽管 C++11 中还没有 auto 的这个用法.

函数参数的 auto

我们刚刚说的都是返回类型的地方放一个 auto . 我们下面来聊聊函数参数中的 auto .

lambda 参数中的 auto

C++ 14 中允许了 lambda 参数使用 auto , auto && 等等 C++14 的类型占位符. 你可以写出这样的代码:

auto sum = [](auto x, auto y) { return x + y; };

sum 就有点像模板了, 遇到的时候会自行推断 x + y 的型别. 尽管如此, 你仍然不能写一个具有函数模板形式的 lambda.

普通函数中的 auto

我们知道长期以来, C++ 有函数模板, 而 lambda 的参数可以用 auto 变得像函数模板一样. 这两个东西这么像, 终于在 C++20 中得到了统一.

在 C++20 中, 我们在函数参数中也可以用 auto , auto & , auto && 等等之一了. 而在 lambda 中, 我们也可以使用显式的模板参数列表了. 你可以写出:

auto add(auto x, auto y)
{
    return x + y;
}

这种很奇怪的代码了.

也可以写出

auto add = []<typename T, typename S>(T x, S y) { return x + y; };

参考:

C++干货系列 - 知乎 (zhihu.com)

C/C++技术 - 知乎 (zhihu.com)

Cpp进阶