走进C++11(九) 类型推导之 auto

走进C++11(九) 类型推导之 auto_第1张图片

 

 

关键字

 

auto

 

语法

(1) (C++11 起) decltype(auto)

(2) (C++14 起) 类型制约 auto

(3) (C++20 起) 类型制约 decltype(auto)

(4) (C++20 起) 类型制约 - 概念名,可以有限定,可以后随 <> 包围的模板实参列表 1,3) 用模板实参推导的规则推导类型。2,4) 类型为 decltype(expr),其中 expr 是初始化器。占位符 auto 可伴随如 const 或 & 这样的修饰符,它们参与类型推导。占位符 decltype(auto) 必须是被声明类型的唯一组分。 (C++14 起)

 

解释

 

这里尽量不提及C++11以后的标准

变量的类型说明符中:auto x = expr;。从初始化器推导类型。若占位符类型说明符为 auto 或 类型制约 auto (C++20 起),则采用从函数调用进行模板实参推导的规则,从初始化器推导变量的类型(细节见其他语境)。例如,给定 const auto& i = expr;,则 i 的类型恰是某个虚构模板 template void f(const U& u) 中参数 u 的类型(假如函数调用 f(expr) 通过编译)。因此,取决于初始化器,auto&& 可被推导成左值引用或右值引用类型,这被用于基于范围的 for 循环。

new 表达式中的类型标识。从初始化器推导类型。对于 new T init(其中 T 含占位符类型,而 init 是带括号的初始化器或带花括号的初始化器列表),如同在虚设的声明 T x init; 中对变量 x 一般推导 T 的类型。

 

用法 

 

C++11中,auto不再是一个存储类型指示符,而是一个自动推导变量的类型。auto并非是一种类型的声明,而是一个类型声明时的“占位符”,编译器在编译期间会将auto替换为变量实际的类型。

 

我觉得auto给我们带来的最大改变有两方面。

 

  1.  解放程序员双手。有了auto这个神器,妈妈再也不用担心我的键盘手了。auto可以代替以前要打的很长很长的变量类型。

     

  2. 还是用在模板推导,下边的例子如果没有auto,x*y就没有办法填写类型了。

template void Multiply(_Tx x, _Ty y){    auto v = x*y;    std::cout << v;}

 

需要注意的是:

 

  • auto 变量必须在定义时初始化,这类似于const关键字。

  • 如果初始化表达式是引用,则去除引用语义。

  • 如果初始化表达式为const或volatile(或者两者兼有),则除去const/volatile语义。

  • 如果auto关键字带上&号,则不去除const语意。

     

const int a2 = 10;auto &b2 = a2;//因为auto带上&,故不去除const,b2类型为const int
  • 初始化表达式为数组时,auto关键字推导类型为指针。

  • 若表达式为数组且auto带上&,则推导类型为数组类型。

  • 函数或者模板参数不能被声明为auto

void func(auto a)  //错误{    //... }
  • 时刻要注意auto并不是一个真正的类型。auto仅仅是一个占位符,它并不是一个真正的类型,不能使用一些以类型为操作数的操作符,如sizeof或者typeid。

cout << sizeof(auto) << endl;//错误cout << typeid(auto).name() << endl;//错误

 

例子

 

#include #include templateauto add(T t, U u) { return t + u; } // 返回类型是 operator+(T, U) 的类型// 在其所调用的函数返回引用的情况下// 函数调用的完美转发必须用 decltype(auto)templatedecltype(auto) PerfectForward(F fun, Args&&... args) {     return fun(std::forward(args)...); }template // C++17 auto 形参声明auto f() -> std::pair // 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);    static_assert(std::is_same_v);    auto c0 = a;             // c0 的类型是 int,保有 a 的副本    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    auto n = {5};    // OK:n 的类型是 std::initializer_list//  auto e{1, 2};    // C++17 起错误,之前为 std::initializer_list    auto m{5};       // OK:C++17 起 m 的类型为 int,之前为 initializer_list//  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 = 3a, after modification through c2 = 4

 

关注公众号获取更多信息:

你可能感兴趣的:(C++11,c++,c++11)