C/C++编程:auto

1059 篇文章 286 订阅

auto初始化表达式可以采用多种形式

  • 通用初始化语法,如 auto a { 42 }; 。
  • 赋值语法,如 auto b = 0;
  • 通用赋值语法,它结合了前两种形式,例如auto c = { 3.14156 };
  • 直接初始化或构造函数样式语法,如 auto d( 1.41421f );
#include <initializer_list>
using namespace std;
int main() {
    auto A = {1, 2};
    auto B = {3};
    auto C{1};
    auto D = {5, 6, 7};
    auto E{8, 9}; //  error: direct-list-initialization of 'auto' requires exactly one element [-fpermissive]
}

作用

自动类型推导

#include <iostream>
using namespace std;

int main()
{
	auto num0 = 10;  
	cout << typeid(num0).name() << endl;
	auto num1 = 10.1;
	cout << typeid(num1).name() << endl;
	auto num2 = 'c';
	cout << typeid(num2).name() << endl;
	auto num3 = "abc";
	cout << typeid(num3).name() << endl;  //char const *
	auto num4 = L"abc";
	cout << typeid(num4).name() << endl;  //wchar_t const *
	return 0;
}

总结:

  • CPP中,auto是一种自适应类型,它会根据初始化的变量而自动推导类型,不能和int,double等关键字相结合
  • auto 让编译器通过初始值来进行类型推演。从而获得定义变量的类型,所以说auto定义的变量必须有初始值

应用场景

  • 当变量类型名很长时使用auto
  • 自动推导类型用auto
  • 当变量类型不确定时用auto

auto与指针

int main()
{
    int* pp = new auto(); //错误	C2119	"new-expression": 无法从空的初始值设定项推导 "auto" 的类型
    auto x = new auto();//错误	C2119	"new-expression": 无法从空的初始值设定项推导 "auto" 的类型

    int* pp1 = new auto(1);  // OK
    auto x1 = new auto(11.1); // OK
    auto* y = new auto(9);  // OK

    double a = 12.34;
    auto *a1 = new auto(x), **a2 = new auto(&a);
	
    return 0;
}
// 每个语句中的所有符号将解析为同一类型。
auto x = 1, *y = &x, **z = &y; // Resolves to int.
auto a(2.01), *b (&a);         // Resolves to double.
auto c = 'a', *d(&c);          // Resolves to char.
auto m = 1, &n = m;            // Resolves to int.

auto与引用

auto与引用

#include <iostream>

using namespace std;

int main( )
{
    int count = 10;
    int& countRef = count;
    auto myAuto = countRef;

    countRef = 11;
    cout << count << " ";

    myAuto = 12;
    cout << count << endl;
}

在这里插入图片描述

在上面的示例中,myAuto 是一个 int ,而不是一个 int 引用. 也就是说:auto将忽略引用

auto不能自动推导成CV-qualifiers(constant& volatile qualifiers),除非被声明为引用类型

#include <iostream>

using namespace std;


int  main()
{
    int a{ 10 };
    cout << typeid(a).name() << endl;    //int
    int &b = a;   //将a的值取出来放入b
    b = 11;
    cout << typeid(b).name() << endl;    //int

    //b是一个引用,去除引用
    int &d = b;
    d = 12;
    cout << typeid(d).name() << endl;    //int
    auto c = b;
    c = 12;
    cout << typeid(c).name() << endl;    //int
    auto &e = b;
    e = 13;
    cout << typeid(e).name() << endl;    //int
   //b,c,e是同一块内存
}

#include <iostream>

using namespace std;

int main()
{
    const int a1{ 10 };
    //a1 = 12;  //C3892    “a1” : 不能给常量赋值    
    cout << "const int a1 = "<< a1 << "\t"<< typeid(a1).name() << endl; //int

    int b1 = a1;
    const auto b2 = a1; //b是新内存,是const int *
    b1 = 12;
    //    b2 = 12;  //C3892    “b2” : 不能给常量赋值    
    cout << "int b1 = " << b1 << "\t" << typeid(b1).name() << endl; //int

    auto c0 = a1; //只是将a1的值赋值过来,是int类型
    c0 = 12;
    cout << "auto c0 = " << c0 << "\t" << typeid(c0).name() << endl;

    //int &c1 = a1; //C2440    “初始化” : 无法从“const int”转换为“int &”    、
    auto &c1 = a1;//b和c是同一块内存
//    c1 = 12;   //C3892    “c1” : 不能给常量赋值    
    cout << "auto &c1 =" << c1 << "\t" << typeid(c1).name() << endl;
}

总结:如果初始化表达式为const或volatile(或者两者兼有),则除去const/volatile语义。如果auto关键字带上&号,则不去除const语意。=是赋值,&是别名

使用auto时,当传递的是const变量的时候,必须手动加上const,因为auto不会自动推倒成const,除非和引用连用。

#include <iostream>

using namespace std;
int main()
{
    const int a = 1;
    const auto b = a;  //b是const auto
    auto c = a;//c的类型为int
    auto& d = a;//d的类型为const int &
}

auto与三目运算符

int v1 = 100, v2 = 200;
auto x = v1 > v2 ? v1 : v2;

auto与函数

int f(int x) { return x; }
int main()
{
    auto x = f(0);
    const auto& y = f(1);
    int (*p)(int x);
    p = f;
    auto fp = p;
    //...
}

auto与数组

auto会退化成指向数组的指针,除非被声明为引用

#include <iostream>

using namespace std;

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

    int a7[3] = { 1, 2, 3 };
    auto & b7 = a7;
    cout << typeid(b7).name() << endl;  //int []
}

auto与for循环

#include <deque>
#include <iostream>
#include <algorithm>
using namespace std;


int  main()
{
    deque<double > dp(10, 0.1);

    if(auto itr = std::find(dp.begin(), dp.end(), 0.1);itr != dp.end()){
        *itr += 4;
    }

    for (auto iter = dp.begin(); iter != dp.end(); ++iter)
    { /* ... */ }
    printf("\n");

    for (auto elem : dp){
        printf("%f\t", elem);  // read only
    }
    printf("\n");

    for (auto& elem : dp){
        elem += 1;  // writeable
    }


    for (const auto& elem : dp){
        printf("%f\t", elem);  // read only
    }
}

在这里插入图片描述

#include <iostream>
using namespace std;
int  main()
{
    int a[5]{ 1, 2, 3, 4, 5 };
    for (auto i : a)   //auto 1是一个副本,会将a内存里面的值原样赋值
    {
        i += 1;
        cout << i << "\t";   //2, ---  6
    }
    cout << "\n";
    for (auto i : a)   //auto 1是一个副本,会将a内存里面的值原样赋值
    {
        cout << i << "\t";   //1, 2, 3, 4, 5
    }
}

在这里插入图片描述
总结:auto i是一个副本,会将数组元素原样赋值给i

如果要修改auto副本:for(auto &i : a),也就是声明为引用

#include <iostream>
using namespace std;
int  main()
{
    int a[5]{ 1, 2, 3, 4, 5 };
    for (auto &i : a)   
    {
        i += 1;
        cout << i << "\t";   //2, ---  6
    }
    cout << "\n";
    for (auto i : a)   
    {
        cout << i << "\t";   //1, 2, 3, 4, 5
    }
}

在这里插入图片描述

使用auto表示多维数组指针

多维数组指针

多维数组是一种常见的数据结构,实际上是数组的数组。这个含义虽然很好理解,但是在定义操作数组数据的指针时却有点麻烦。假设有下面的二维数组。

int matrix[10][10];

定义指向其中一行的指针时,下面那种方式是对的呢?

int *row[10];
int (*row)[10];

答案是第二种。这里硬记当然是一种办法,但是也可以用换一个方式看代码:

int*        row[10];
int         (*row)[10];

第一种情况是指针的数组,剩下的就是数组的指针了。

C++11的处理方式

C++11之后,有了auto描述符,有了begin、end函数,定义多维数组指针的时候就可以容易一些了,例如可以这样写代码:

int matrix[10][10];

int number = 1;

for(auto row = begin(matrix); row != end(matrix); ++row)
 {
       for(auto data = begin(*row); data != end(*row); ++data){
           *data = number++;
       }
 }

因为row是数组指针,而begin和end的要求的是引用类型,所以在调用begin和end函数取得数据指针时使用的参数是*row,而不是row。

返回值占位

#include <iostream>

using namespace std;
using namespace std;
template <typename T1, typename T2>
auto compose1(T1 t1, T2 t2)
{
    return t1 + t2;
}

template <typename T1, typename T2>
auto compose2(T1 t1, T2 t2) -> decltype(t1 + t2)
{
    return t1 + t2;
}
int main()
{
    cout << compose1(1, 11.1) << endl;
    cout << compose2(1, 11.1) << endl;
}

在这里插入图片描述
总结:

函数模板中,与decltype结合表示函数返回的类型

  • decltype操作符用于查询表达式的数据类型。
  • auto在这里的作用也称为返回值占位,它只是为函数返回值占了一个位置,真正的返回值是后面的decltype(t1 + t2)

当模板函数的返回值依赖于模板的参数时,我们依旧无法在编译代码前确定模板参数的类型,故也无从知道返回值的类型,这时我们可以使用auto。

注意

auto是类型的占用符,但它本身不是类型。因此,不能用sizeof(auto)或者typeid(auto)

#include <iostream>
using namespace std;
int  main()
{
    cout << sizeof(auto) << endl;//错误
    cout << typeid(auto).name() << endl;//错误
}

auto 关键字不能与任何其他类型说明符组合。

int main()
{
    //错误原因: 因为变量 x 同时用 auto 关键字和类型声明 int 
    auto int x;   // C3530:  error: two or more data types in declaration of 'x'
    return 0;
}

在这里插入图片描述

使用关键字声明的符号 auto 必须具有初始值设定项

int  main()
{
    auto i;  //error: declaration of 'auto i' has no initializer
    return 0;
}

在这里插入图片描述

auto 关键字不能声明数组

在这里插入图片描述

int  main()
{
    auto a[5];            // C3532
    auto b[1][2];         // C3532
    auto y[5] = x;        // C3532
    auto z[] = {1, 2, 3}; // C3532
    auto w[] = x;         // C3532
    return 0;
}

在这里插入图片描述

不要将模板参数指定为 auto 关键字(考虑重载的问题,我们应该使用模板)。

在这里插入图片描述

#include <iostream>

using namespace std;

template<class T> class C{};
int main()
{
    C<auto> c;   // C3539
    return 0;
}

在这里插入图片描述

//不能将变量强制转换为指定的类型**:

int main()
{
    int value = 123;
    auto(value);                        // C3537
    (auto)value;                        // C3537
    auto x1 = auto(value);              // C3537
    auto x2 = (auto)value;              // C3537
    auto x3 = static_cast<auto>(value); // C3537\
    auto  p = auto(3);

    return 0;
}

在这里插入图片描述

在声明符列表中,“auto”必须始终推导为同一类型

//  每个语句声明多个变量,但关键字的每个使用都 auto 不能推导为同一类型。
int main()
{
// Variable x1 is a pointer to char, but y1 is a double.
   auto * x1 = "a", y1 = 3.14;
// Variable c is a char and c1 is char*, but c2, and c3 are pointers to pointers.
   auto c = 'a', *c1 = &c, * c2 = &c1, * c3 = &c2;
// Variable x2 is an int, but y2 is a double and z is a char.
   auto x2(1), y2(0.0), z = 'a';
// Variable a is a pointer to int, but b is a pointer to double.
   auto *a = new auto(1), *b = new auto(2.0);
   return 0;
}

其他

void f(){}
int main()
{
    auto x = f();   //因为初始化表达式的计算结果为 void 
    return 0;
}

在这里插入图片描述

// C3535b.cpp
// Compile with /Zc:auto
int main()
{
   auto* x = 123.0;   // C3535:因为该语句将变量声明 x 为指向推导出的类型的指针,而初始值设定项表达式的类型为 double。 因此,编译器无法推导出变量的类型。
   return 0;
}

在这里插入图片描述

int main()
{
    class A { };
    A x;
    auto *p = x;  // C3535: 因为变量 p 声明指向推导出的类型的指针,但初始化表达式不是指针类型
    return 0;
}

在这里插入图片描述

建议

建议你在 auto 大多数情况下使用关键字,除非你确实需要转换,因为它具有以下优势:

  • 可靠性: 如果表达式的类型发生更改(这包括在函数返回类型发生更改时),则它将正常工作。
  • 性能: 您可以保证不会进行任何转换。
  • 可用性: 无需担心类型名称拼写错误和拼写错误。
  • 效率: 你的编码可能更高效

http://c.biancheng.net/view/6984.html
https://docs.microsoft.com/zh-cn/cpp/cpp/auto-cpp

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值