zoukankan      html  css  js  c++  java
  • 【C++11】第一篇:新关键字

    auto
    auto是在编译时对变量进行类型推导,从初始化表达式中推断出变量的数据类型。
    如下代码
     1 #include <stdio.h>
     2 #include <vector>
     3 
     4 using namespace std;
     5 int* f()
     6 {
     7      int *p = new int();
     8      *p = 2;
     9 
    10      return p;
    11 }
    12 
    13 int main()
    14 {
    15      auto a;
    16      auto i = 2;
    17      auto s = "hello";
    18 
    19      printf("%s %d
    ", s, i);
    20 
    21      vector<int> vec{1, 2, 3, 4, 5};
    22 
    23      auto it = vec.begin();
    24      auto end = vec.end();
    25 
    26      for (; it != end; ++it)
    27      {
    28           printf("%d ", *it);
    29      }
    30      printf("
    ");
    31 
    32      auto a = f();
    33      auto* b = f();
    34 
    35      printf("a=%d *a= %d b=%d *b=%d
    ", a, *a, b, *b);
    36      
    37      return 0;
    38 }

    编译结果

    root@yzj-VirtualBox:/home/wzw/workstation/c++11# g++ -std=c++11 test.cpp -o test
    test.cpp: 在函数‘int main()’中:
    test.cpp:8:7: 错误:‘auto a’声明有缺少初始值设定
      auto a;

    第一次编译,失败。原因是auto a;没有初始化。

    因为auto是通过初始化表达式进行类型推导的,所以这样的代码无法对a进行类型确定,是自动推导,但也没这么智能啊,所以该程序员做的事,还得做。
    好了,把auto a;注释掉,再编译一次运行看结果吧。
    root@yzj-VirtualBox:/home/wzw/workstation/c++11# g++ -std=c++11 test.cpp -o test
    root@yzj-VirtualBox:/home/wzw/workstation/c++11# ./test
    hello 2
    1 2 3 4 5 
    a=7163952 *a= 2 b=7163984 *b=2
    上面的代码发现了几个亮点呢?
    1、可以不理会变量的类型,只要在定义时进行初始化,即时是指针也可以不显示的定义成auto*,同理引用、const等等也可以不显示(不过个人认为还是显示比较好,免得阅读障碍)。
    2、对于STL迭代器,在auto变量引入之前我们需要vector<int>::iterator it = vec.begin();这样来定义,而现在auto it = vec.begin();不但在编码时候效率提高了,视觉上也感觉清新舒爽了很多有没有?
    3、vec的初始化看到没?直接在{}中初始化,和数组的初始化一样一样的啊。这也是C++11的一个新特性,初始化列表。此处不细说,后面再说。
    其实auto的好处还不止这些,在模板中会更爽。
    比如下面这个函数
    1 template <typename Product, typename Builder>
    2 void BuidProduct(const Builder& builder)
    3 {
    4     Product val = builder.buildObj();
    5      //....
    6 }

    使用auto变量以后可以省掉一个模板参数,不信请看。

    1 template <typename Builder>
    2 void BuidProduct(const Builder& builder)
    3 {
    4      auto val = builder.buildObj();
    5      //....
    6 }

    爽不爽?不爽我们继续。

    decltype 

    作用和auto相反,可以从一个变量或表达式中得到类型,在有些语言中可以有Type或者getType等方法。比如说

    int i = 1;
    decltype(i) j = 2;

    下面,没有了?当然不是,请看下面。

    继续说上面的模板,如果要BuildProduct需要将val返回,那返回类型怎么办呢?我们不是有auto吗?没错,有auto。但是光有auto还不行,不过你得这么干才行。

    1 template <typename Builder>
    2 auto BuidProduct(const Builder& builder) -> decltype(builder.buildObj())
    3 {
    4      auto val = builder.buildObj();
    5      //....
    6      return val;
    7 }

    注意红色字体部分,在C++11中,可以把返回类型放在函数后面,用auto代替前面的返回类型。如果不加这句会什么效果呢?

    编译结果如下:

    testauto.cpp:55:41: 错误:‘BuildProduct’ function uses ‘auto’ type specifier without trailing return type

    所以这是不能少滴。

    nullptr
    咦?我们不是有NULL了吗,还要加这么个破玩意儿干啥?注意,请注意,这不是破玩意儿。这是为了解决NULL二义性问题而加入的。因为地球人都知道NULL其实就是0。

    空口无凭,有代码为证

     1 #include <iostream>
     2 
     3 using namespace std;
     4 
     5 void f(int i)
     6 {
     7      cout << i << endl;
     8 }
     9 
    10 void f(int *p)
    11 {
    12      if(NULL != p)
    13      {
    14           cout << p << endl;
    15      }
    16 }
    17 
    18 int main()
    19 {
    20      int *p = nullptr;
    21      int *q = NULL;
    22      
    23      int a = nullptr;
    24      int b = NULL;
    25      
    26      f(0);
    27      f(nullptr);
    28 
    29      return 0;
    30 }

    编译结果如何?你猜!

    root@yzj-VirtualBox:/home/wzw/workstation/c++11# g++ -std=c++11 testnullptr.cpp -o testnullptr
    testnullptr.cpp: 在函数‘int main()’中:
    testnullptr.cpp:23:10: 错误:不能在初始化时将‘std::nullptr_t’转换为‘intint a = nullptr;
              ^
    testnullptr.cpp:24:13: 警告:将 NULL 转换到非指针类型‘int’ [-Wconversion-null]
         int b = NULL;

    看到没,int a = nullptr;报错,而int b = NULL;只是警告。说明啥?nullptr不能强制转换成int,而NULL可以。

    f(0);这个调用,如果不是在C++11中也会编译失败,为啥?因为它有二义性,f(int)和f(int *)傻傻分不清。而在C++11中就明确的调用f(int)。

    序列for循环

    又一个节省编码量的特性,可以用于遍历数组、容器、string以及定义了begin、end以及iterator的自定义序列,如下列代码:

     1 #include <iostream>
     2 #include <string>
     3 #include <map>
     4 
     5 using namespace std;
     6 
     7 int main()
     8 {
     9      map<string, int> m{{"a", 1}, {"b", 2}, {"c", 3}};
    10 
    11      for (auto p : m)
    12      {
    13          cout << p.first << " : " << p.second << endl;
    14      }
    15 
    16      return 0;
    17 }

    清新舒爽有木有?这句话怎么像WSJ广告里面的啊?

    最后回来说是初始化列表的事儿吧

    我们知道,在C++11之前只有数组可以用初始化列表,而在C++11中C++11新添加初始化列表 std::initializer_list<>类型,可以通过{}语法来构造初始化列表 ,所以vector、list等容器,string以及自定义结构体、类、函数都可以使用初始化列表。请看代码
    #include <vector>
    #include <string>
    #include <unordered_map>
    #include <iostream>
    
    using namespace std;
    
    void foo(initializer_list<float> list)
    {
        for (auto iter = list.begin(); iter != list.end(); ++iter)
        {
            cout << *iter << ", ";
        }
    
        cout << endl << list.size() << endl;
    }
    
    int main()
    {
        foo({1.0f, 3.7f, 8.9f});
    
        vector<string> v1 = {"hello", "world", "welcome"};
        vector<int> v2 = {0, 3, 8, 1, 4};
    
        unordered_map<int, string> dictionary = {
            {1, "one"},
            {2, "two"},
            {3, "three"}
        };
    
        for (auto i : dictionary) {
            cout << i.first << " -> " << i.second << endl;
        }
    }

     好了,这回下面真的没有了。

     且听下回分解。。。
  • 相关阅读:
    bzoj2888: 资源运输
    [ SDOI 2009 ] HH的项链 & [ HEOI 2012 ] 采花
    [ POI 2017 ] Podzielno
    [ HAOI 2011 ] Problem A
    [ SDOI 2011 ] 打地鼠
    [ SCOI 2007 ] Perm
    [ POI 2011 ] Dynamite
    [ BZOJ 3038 & 3211 / SPOJ GSS4 ] 上帝造题七分钟2 / 花神游历各国
    [ BZOJ 3445 ] Roadblock
    [ ZJOI 2006 ] Mahjong
  • 原文地址:https://www.cnblogs.com/zhiqli/p/3964825.html
Copyright © 2011-2022 走看看