一、进行自动类型推导

  • auto 的自动类型推断发生在编译期,所以使用 auto 并不会造成程序运行时效率的降低。
  • 而是否会造成编译期的时间消耗,我认为是不会的,在未使用 auto 时,编译器也需要得知右操作数的类型,再与左操作数的类型进行比较,检查是否可以发生相应的转化,是否需要进行隐式类型转换。
  • auto 属于类类型推导
  • decltype 是包含声明修饰符的声明类型推导
int main()
{
    int a = 10;
    auto val = a;
    cout << typeid(val).name() << endl;       // i
    return 0;
}

二、在定义函数模板时,用于声明依赖模板参数的变量类型

不到编译的时候,x * y 的真正类型很难确定

template <class _Tx,class _Ty>
void Multiply(_Tx x, _Ty y)
{
    auto v = x * y;
    std::cout << v;
}
int main()
{
    int a = 10;
    double b = 1.53;
    Multiply(a, b);     // 15.3
    return 0;
}

三、函数模板返回值依赖于模板参数

auto 在这里的作用也称为返回值占位,真正的返回值是后面的 decltype(x * y)。为何要将返回值后置呢?如果没有后置,则函数声明时为:decltype(x * y) multiply(_Tx x, _Ty y),而此时 x, y 还没声明呢,编译无法通过。

template <class _Tx,class _Ty>
auto Multiply(_Tx x, _Ty y) -> decltype(x * y)
{
    return x * y;
}
int main()
{
    int a = 10;
    double b = 1.53;
    cout << Multiply(a, b) << endl;
    return 0;
}

四、与匿名函数结合使用

int main()
{
    auto f = [](int a, int b) -> int
    {
        return a * b;
    };
 
    decltype(f) g = f;  // lambda 的类型是独有且无名的
                        // 也不用定义函数指针了
    cout << typeid(f).name() << endl;
    auto i = f(2, 2);
    decltype(g(3, 3)) j = g(3, 3);
 
    cout << "i = " << i << ", "
         << "j = " << j << '\n';
    return 0;
}

输出:

Z4mainEUliiE_
i = 4, j = 9

五、auto 注意事项

  1. auto 变量必须在声明时初始化,这类似于 const 关键字。

  2. 定义在一个 auto 序列的变量必须始终推导成同一类型。

    auto a4 = 10, a5 = 20, a6 = 30; //正确
    auto b4 = 10, b5 = 20.0, b6 = 'a'; //错误
    
  3. 如果初始化表达式是引用,则去除引用语义

    int main()
    {
        int a = 10;
        int &b = a;
    
        auto c = b;     // c的类型为int而非int&(去除引用)
        auto &d = b;    // 此时c的类型才为int&
    
        c = 100;    //a = 10;
        cout << "c = " << c << " a = " << a << endl;
        d = 100;    //a = 100;
        cout << "d = " << d << " a = " << a << endl;
        return 0;
    }
    

    输出:

    c = 100 a = 10
    d = 100 a = 100
    
  4. 如果初始化表达式为 const 或 volatile(或者两者兼有),则除去 const/volatile 语义

  5. 如果 auto 关键字带上 & 号,则不去除 const 语义

    int main()
    {
        const int a1 = 10;
    
        auto  b1= a1;       // b1的类型为int而非const int(去除const)
        // 与指针类似,只是为新变量开辟了新的空间
        int* pB1 = (int*)&a1;
        b1 = 100;           // 合法
        *pB1 = 1000;        // 合法
        cout << "b1 = " << b1 << endl;
        cout << "a1 = " << a1 << endl;
        cout << "*pB1 = " << *pB1 << endl;
    
        const auto c1 = a1; // 此时c1的类型为const int
        // c1 = 100;           // 非法
    
    
        auto& b2 = a1;      // 因为auto带上&,故不去除const,b2类型为const int
        // b2 = 100;        // 非法
    
        return 0;
    }
    

    输出:

    b1 = 100
    a1 = 10
    *pB1 = 1000
    
  6. 初始化表达式为数组时,auto 关键字推导类型为指针。

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

    int main()
    {
        int a3[3] = { 1, 2, 3 };
        auto b3 = a3;
        cout << typeid(b3).name() << endl;
    
        auto& c3 = a3;  // int (&)[3]
        cout << typeid(c3).name() << endl;
        return 0;
    }
    

    输出:

    Pi
    A3_i
    
  8. 函数形参或者模板参数不能被声明为 auto。

六、decltype 声明引用类型

struct A { double x; };
const A* a;
 
decltype(a->x) y;       // y 的类型是 double(其声明类型)
decltype((a->x)) z = y; // z 的类型是 const double&(左值表达式)