initializer_list中的const auto& 问题

 void error_msg(ErrCode e, initializer_list<string> il)
{
    cout << e.msg() << ":";
    for (const auto &elem : il)
        cout << elem << " ";
    cout << endl;
}

initializer_list对象中的元素永远是常量值,但是为什么范围

for循环中,elem的类型是const auto&类型?又不能修改initializer_list对象中的值,为什么要用&符号?


--------------------------------------------

用引用做参数比对象效率高。

C语言中,就有了auto关键字,它被当作是一个变量的存储类型修饰符,表示自动变量(局部变量)。它不能被单独使用,否则编译器会给出警告。在C++11标准中,添加了新的类型推导特性。在C ++11中,使用auto定义的变量不能使用其它类型修饰符修饰,该变量的类型由编译器根据初始化数据自动确定。

C++中类型检查是在编译阶段。动态类型语言能做到在运行时决定类型,主要归功于一技术,这技术是类型推导。在C++11中,可以通过重定义auto关键字来实现类型推导。

         在C++11中,使用auto关键字可以要求编译器对变量的类型进行自动推导。

         auto关键字:类型推导,从该关键字的初始化表达式中推导变量的类型。

         在块作用域、命名空间作用域、for循环的初始化语句内声明变量的时候,变量的类型可以被省略,使用关键字auto来代替。

         auto声明的变量必须被初始化,以使编译器能够从其初始化表达式中推导出其类型。

         声明为auto的变量在编译时期就分配了内存,而不是到了运行时期,所以使用auto不再引发任何速度延迟,这也意味着使用auto的时候,这个变量不初始化会报错,因为编译器无法知道这个变量的类型。

         auto使用时需注意:

         (1)、可以使用const、volatile、pointer(*)、reference(&)、rvalue reference(&&)等说明符和声明符来修饰auto关键字;

         (2)、用auto声明的变量必须初始化;

         (3)、auto不能与其它任何类型说明符一起使用;

         (4)、方法、参数或模板参数不能被声明为auto;

         (5)、定义在堆上的变量,使用了auto的表达式必须被初始化;

         (6)、auto是一个占位符,不是类型,不能用于类型转换或其它一些操作,如sizeof、typeid;

         (7)、auto关键字内声明的声明符列表的所有符号必须解析为同一类型;

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

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

         (10)、auto不能作为函数的返回类型,在C++14中是可以的。

         建议:大多数情况使用关键字auto,除非非常需要转换。

下面是从其他文章中copy的测试代码,详细内容介绍可以参考对应的reference:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #include "auto.hpp"  
  2. #include <iostream>  
  3. #include <cmath>  
  4. #include <typeinfo>  
  5. #include <string>  
  6. #include <map>  
  7. #include <list>  
  8. #include <deque>  
  9. #include <vector>  
  10.   
  11. //  
  12. // reference: http://en.cppreference.com/w/cpp/language/auto  
  13. template<class T, class U>  
  14. auto add(T t, U u) -> decltype(t + u) // the return type is the type of operator+(T, U)  
  15. {  
  16.     return t + u;  
  17. }  
  18.   
  19. auto get_fun(int arg) -> double(*)(double// same as: double (*get_fun(int))(double)  
  20. {  
  21.     switch (arg) {  
  22.         case 1: return std::fabs;  
  23.         case 2: return std::sin;  
  24.         defaultreturn std::cos;  
  25.     }  
  26. }  
  27.   
  28. int test_auto1()  
  29. {  
  30.     auto a = 1 + 2;  
  31.     std::cout << "type of a: " << typeid(a).name() << '\n'// type of a: int  
  32.     auto b = add(1, 1.2);  
  33.     std::cout << "type of b: " << typeid(b).name() << '\n'// type of b: double  
  34.     auto c = { 1, 2 };  
  35.     std::cout << "type of c: " << typeid(c).name() << '\n'// type of c: class std::initializer_list<int>  
  36.   
  37.     auto my_lambda = [](int x) { return x + 3; };  
  38.     std::cout << "my_lambda: " << my_lambda(5) << '\n'// my_lambda: 8  
  39.   
  40.     auto my_fun = get_fun(2);  
  41.     std::cout << "type of my_fun: " << typeid(my_fun).name() << '\n'// type of my_fun: double (__cdecl*)(double)  
  42.     std::cout << "my_fun: " << my_fun(3) << '\n'// my_fun: 0.14112  
  43.   
  44.     // auto int x; // error as of C++11: "auto" is no longer a storage-class specifier // error C3530: “auto”不能与任何其他类型说明符组合  
  45.   
  46.     return 0;  
  47. }  
  48.   
  49.   
  50. // reference: https://msdn.microsoft.com/zh-cn/library/dd293667(v=vs.120).aspx  
  51. int f(int x) { return x; }  
  52.   
  53. int test_auto2()  
  54. {  
  55.     int count = 10;  
  56.     int& countRef = count;  
  57.     auto myAuto = countRef;  
  58.   
  59.     countRef = 11;  
  60.     std::cout << count << " " << std::endl; // 11  
  61.   
  62.     myAuto = 12;  
  63.     std::cout << count << std::endl; // 11  
  64.   
  65.     // 1. 下面的声明等效。 在第一个语句中,声明 j 变量为类型 int。 在第二个语句,因为初始化表达式 (0) 是整数,所以变量 k 推导为 int 类型  
  66.     int j = 0;  // Variable j is explicitly type int.  
  67.     auto k = 0; // Variable k is implicitly type int because 0 is an integer.  
  68.   
  69.     // 2. 以下声明等效,但第二个声明比第一个简单  
  70.     std::map<int, std::list<std::string>> m;  
  71.     std::map<int, std::list<std::string>>::iterator i = m.begin();  
  72.     auto i_ = m.begin();  
  73.   
  74.     // 3. 声明 iter 和 elem 变量类型  
  75.     std::deque<double> dqDoubleData(10, 0.1);  
  76.   
  77.     for (auto iter = dqDoubleData.begin(); iter != dqDoubleData.end(); ++iter) { /* ... */}  
  78.   
  79.     // prefer range-for loops with the following information in mind  
  80.     // (this applies to any range-for with auto, not just deque)  
  81.   
  82.     for (auto elem : dqDoubleData) // COPIES elements, not much better than the previous examples   
  83.     { /* ... */ }  
  84.   
  85.     for (auto& elem : dqDoubleData) // observes and/or modifies elements IN-PLACE  
  86.     { /* ... */ }  
  87.   
  88.     for (const auto& elem : dqDoubleData) // observes elements IN-PLACE  
  89.     { /* ... */ }  
  90.   
  91.     // 4. 使用 new 运算符  
  92.     double x = 12.34;  
  93.     auto *y = new auto(x), **z = new auto(&x);  
  94.   
  95.     // 5. 所有符号解析为同一类型  
  96.     auto x_ = 1, *y_ = &x_, **z_ = &y_; // Resolves to int.  
  97.     auto a(2.01), *b(&a);         // Resolves to double.  
  98.     auto c = 'a', *d(&c);          // Resolves to char.  
  99.     auto m_ = 1, &n_ = m_;            // Resolves to int.  
  100.   
  101.     // 6. 使用条件运算符 (?:)  
  102.     int v1 = 100, v2 = 200;  
  103.     auto e = v1 > v2 ? v1 : v2;  
  104.   
  105.     // 7. 将变量 x7 初始化类型 int,将引用的变量 y7 初始化为类型 const int,及将变量 fp 初始化为指向返回类型 int 的函数的指针  
  106.     auto x7 = f(0);  
  107.     const auto & y7 = f(1);  
  108.     int(*p)(int x7);  
  109.     p = f;  
  110.     auto fp = p;  
  111.   
  112.     return 0;  
  113. }  
  114.   
  115. /  
  116. // reference: http://www.learncpp.com/cpp-tutorial/4-8-the-auto-keyword/  
  117. int add_3(int x, int y)  
  118. {  
  119.     return x + y;  
  120. }  
  121.   
  122. int test_auto3()  
  123. {  
  124.     auto d = 5.0; // 5.0 is a double literal, so d will be type double  
  125.     auto i = 1 + 2; // 1 + 2 evaluates to an integer, so i will be type int  
  126.   
  127.     auto sum = add_3(5, 6); // add_3() returns an int, so sum will be type int  
  128.   
  129.     return 0;  
  130. }  


编程时常常需要把表达式的值赋给变量,这就要求在声明变量的时候清楚知道表达式的类型。然而要做到这一点并非那么容易,有时候甚至根本做不到。为了解决这个问题,C++11标准引入了auto类型说明符,用它就能让编译器替我们去分析表达式所属的类型。

与原来那些只对应一种特定类型的说明符不同,auto让编译器通过初值来推算变量类型。显然,auto定义的变量必须要有初始值。

使用auto具有以下几点好处:

  • 可靠性:如果表达式的类型发生更改(包括函数返回值发生更改的情况),它也能工作。
  • 性能:确保将不会进行转换。
  • 可用性:不必担心类型名称拼写困难和拼写有误。
  • 效率:代码会变得更高效。
auto item = val1 + val2; // 由val1和val2相加的结果推断出item的类型

auto i=0, *p = &i; // i是整数,p是整型指针
 
 
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

使用auto能在一条语句中声明多个变量。但是一条声明语句只能有一个基本数据类型,所以该语句中所有变量的初始基本数据类型都必须一致:

auto sz = 0, pi = 3.14; // Error!
 
 
  • 1
  • 1

编译器推断出的auto类型有时候和初始值的类型并不完全一样,编译器会适当地改变结果类型使其更符合初始化规则,例如:

  • 使用auto会删除引用
int count = 10;
int& countRef = count;
auto myAuto = countRef;

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

myAuto = 12;
cout << count << endl; // print 11
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

你可能会认为 myAuto 是一个 int 引用,但它不是。它只是一个 int,因为输出为 11 11,而不是 11 12;如果 auto 尚未删除此引用,则会出现此情况。

  • const限定符 
    先引入一种表述:顶层const表示指针本身是个常量,底层const表示指针所指的对象是一个常量。一般auto会忽略掉顶层const,同时底层const则会保留下来,例如:
int i = 0;
const int ci = i, &cr = ci;
auto b = ci;  // b 是一个整数(ci的顶层const特性被忽略掉)
auto c = cr;  // c 是一个整数(cr是ci的别名,ci本身是一个顶层const)
auto d = &i;  // d 是一个整型指针(整数的地址就是指向整数的指针)
auto e = &ci; // e 是一个指向整数常量的指针(对常量对象取地址是一种底层const)
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

如果希望推断出的auto类型是一个顶层const,需要明确指出:

const auto f = ci; // ci 的推演类型是int,f是const int类型
 
 
  • 1
  • 1

还可以将引用的类型设置为auto,此时原来的初始化规则仍然适用:

auto &g = ci; // g是一个整型常量引用,绑定到ci
auto &h = 42; // Error: 不能为非常量引用绑定字面值
const auto &j = 42; // OK: 可以为常量引用绑定字面值
 
 
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

切记,符号*&只从属于某个声明,而非基本数据类型的一部分,因此初始值必须是同一类型:

auto k = ci, &l = i; // k是整数,l是整型引用
auto &m = ci, *p = &ci; // m是对整型常量的引用,p是指向整型常量的指针
auto &n = i, *p2 = &ci; // Error: i的类型是int,而&ci的类型是const int
 
 
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

附上更多示例代码:

  • 下面的声明等效。在第一个语句中,将变量j 声明为类型 int。在第二个语句中,将变量 k 推导为类型 int,因为初始化表达式 (0) 是整数
int j = 0;  // Variable j is explicitly type int.
auto k = 0; // Variable k is implicitly type int because 0 is an integer.
 
 
  • 1
  • 2
  • 1
  • 2
  • 以下声明等效,但第二个声明比第一个更简单。使用 auto 关键字的最令人信服的一个原因是简单
map<int,list<string>>::iterator i = m.begin(); 
auto i = m.begin(); 
 
 
  • 1
  • 2
  • 1
  • 2
  • 使用 iter 和 elem 启动循环时
#include <deque>
using namespace std;

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

    for (auto iter = dqDoubleData.begin(); iter != dqDoubleData.end(); ++iter)
    { /* ... */ }

    // prefer range-for loops with the following information in mind
    // (this applies to any range-for with auto, not just deque)

    for (auto elem : dqDoubleData) // COPIES elements, not much better than the previous examples
    { /* ... */ }

    for (auto& elem : dqDoubleData) // observes and/or modifies elements IN-PLACE
    { /* ... */ }

    for (const auto& elem : dqDoubleData) // observes elements IN-PLACE
    { /* ... */ }
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 下面的代码片段使用 new 运算符和指针声明来声明指针
double x = 12.34;
auto *y = new auto(x), **z = new auto(&x);
 
 
  • 1
  • 2
  • 1
  • 2
  • 下一个代码片段在每个声明语句中声明多个符号。请注意,每个语句中的所有符号将解析为同一类型。
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.
 
 
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4
  • 此代码片段使用条件运算符 (?:) 将变量 x 声明为值为 200 的整数:
int v1 = 100, v2 = 200;
auto x = v1 > v2 ? v1 : v2;
 
 
  • 1
  • 2
  • 1
  • 2
  • 下面的代码片段将变量 x 初始化为类型 int,将变量 y初始化对类型 const int 的引用,将变量 fp 初始化为指向返回类型 int 的函数的指针。
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;
    //...
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10


  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值