1) 在块作用域、命名空间作用域、循环初始化语句等中声明变量时,关键词
auto 可用作类型指定符。
只要初始化器的类型被确定,则编译器会用来自函数调用的模板实参推导规则所决定的类型替换关键词 auto (细节见模板实参推导)。关键词 auto 可与修饰符组合,如 const 或 & ,它们将参与类型推导。例如,给出 const auto& i = expr; , i
的类型恰是虚构模板 template<class U> void f(const U& u) 中参数 u
的类型,倘若函数调用 f(expr) 被编译。从而, auto&& 可根据初始化器被推导成左值或是右值引用,这被用于基于范围的for循环。
9)
结构化绑定声明
注意
C++11 前, auto 拥有存储期指定符的语义。
不允许在一个声明中混合 auto
变量和函数,如 auto f() -> int, i = 0; 。
示例
运行此代码
#include <iostream> #include <utility> template<class T, class U> auto add(T t, U u) { return t + u; } // 返回类型是 operator+(T, U) 的类型 // 在其所调用的函数返回引用的情况下 // 函数调用的完美转发必须用 decltype(auto) template<class F, class... Args> decltype(auto) PerfectForward(F fun, Args&&... args) { return fun(std::forward<Args>(args)...); } template<auto n> // C++17 auto 形参声明 auto f() -> std::pair<decltype(n), decltype(n)> // auto 不能从花括号初始化器列表推导 { return {n, n}; } int main() { auto a = 1 + 2; // a 的类型是 int auto b = add(1, 1.2); // b 的类型是 double static_assert(std::is_same_v<decltype(a), int>); static_assert(std::is_same_v<decltype(b), double>); decltype(auto) c1 = a; // c1 的类型是 int ,保有 a 的副本 decltype(auto) c2 = (a); // c2 的类型是 int& ,为 a 的别名 std::cout << "a, before modification through c2 = " << a << '\n'; ++c2; std::cout << "a, after modification through c2 = " << a << '\n'; auto [v, w] = f<0>(); // 结构化绑定声明 auto d = {1, 2}; // OK : d 的类型是 std::initializer_list<int> auto n = {5}; // OK : n 的类型是 std::initializer_list<int> // auto e{1, 2}; // C++17 起错误,之前为 std::initializer_list<int> auto m{5}; // OK : C++17 起 m 的类型为 int ,之前为 initializer_list<int> // decltype(auto) z = { 1, 2 } // 错误: {1, 2} 不是表达式 // auto 常用于无名类型,例如 lambda 表达式的类型 auto lambda = [](int x) { return x + 3; }; // auto int x; // 于 C++98 合法, C++11 起错误 // auto x; // 于 C 合法,于 C++ 错误 }
可能的输出:
a, before modification through c2 = 3 a, after modification through c2 = 4