• C++11 麻辣烫


    C++11

    空格

    vector<list<list> >; // C++11之前需要一个空格
    vector<list<list>>;  // OK 在C++11之后 
    

    nullptr和std::nullptr_t

    // 空指针可以设置成 nullptr
    void f(int);
    void f(void*);
    f(0);            // call f(int)
    f(NULL);         // call f(int) if NULL == 0
    f(nullptr);      // call f(void*) 
    typedef decltype(nullptr) nullptr_t; // 所以nullptr_t就是nullptr的类型
    

    decltype

    // 用于定义变量而不必关注类型
    int i;
    decltype(i) a;
    

    类型自动推导

    auto a = {1,2}; // a是一个int类型,用于模板和lambda函数的返回值等复杂类型的情况
    

    变量初始化的 标准化,全部都可以用大括号初始化变量,幕后是array结构在支撑

    int val[] {1, 2, 3};
    vector<int> vec{1, 2, 3};
    vector<string> cites{"a", "a", "a", "a", "a", "a"};
    

    initializer lists (值得重看)

    int i;    // i有未定义的值
    int j{};  // j 初始化成0
    int* p;   // p有未定义的值
    int* q{}; // q被初始化成nullptr
    
    int x1(5.1);  // OK,但是x1会是5
    int x2 = 5.3; // OK,但是x2会是5
    int x3{5.3};  // ERROR,强制转换失败
    int x4 = {5.3}; // ERROR,强制转换失败
    
    class P {
      P(int a, int b) 
      {
        cout << a << b << endl;
      }
      P(initializer_list<int> il) 
      {
        for (auto &i :il) 
          cout << i << " ";
        cout << endl;
      }
    }
    P p(3, 5);	// 调用P(int a, int b)
    P p{3, 5};  // 调用P(initializer_list il),但是没有这个函数的时候就调用另一个构造函数了
    P p{1, 3, 6};  // 调用P(initializer_list il)
    
    int a = min{1, 3, 5};    // 原来的min版本只能求2个元素的最小值,现在可以求不限个数了
    
    

    explict

    // 用途很少,主要用在构造函数, 防止隐式转换,下面是例子
    Class Complex
    {
      int real, img;
      explict /* 告诉编译器要执行严格的类型转换 */
      Complex(int re, int im = 0) : real(re), img(im)
      {}
      Complex operator+(const, Complex& x) 
      { return Complex(real + x.real, img + x.img);}
    };
    

    新的for循环

    for (decl : coll) 
    { statement; }
    

    =default 和 =delete

    以下面的例子为例:

    Class Zoo
    {
    public:
      Zoo(int il1, int il1) : il1(i1), il2(i2) {}
      Zoo(const Zoo&) = delete;
      Zoo(Zoo&&) = default;
      Zoo& operator = Zoo(const Zoo&) = default;
      Zoo& operator = Zoo(const Zoo&&) = delete;
      vitual ~Zoo();
    private:
      int i1, i2;
    };
    

    原来的情况是如果你写了上面的一个类,但是没有定义任何的ctor(包括无参构造函数、析构函数、拷贝构造函数、参数是引用的move构造函数、赋值构造函数和参数是引用的move构造函数),C++编译器将会帮你写出来;但是只要你主动声明了这些函数,C++编译器就不会做这个事情。

    那么现在如果对其中的某个函数加上了delete就表示不需要这个函数。 而如果加上了delete就表示需要这个函数。

    btw:如果default用在其他函数的话,没有意义,只会编译报错;如果delete则

    Alias(别名) Template (template typedef)

    原本可以用typedef就有相似的功能,可是有无法传递参数的短板。

    现在用using创建别名,就不会有这样的短板。

    当然,不仅与此,别名可以处理模板的模板参数,二阶模板参数

    值得回味。

    类型的化名

    还是using。

    1. 函数指针:typedef void (*)(int, int);变成using func = void (*)(int, int)
    2. 模板的化名:template<class CharT> using mystring = std::basic_string<CharT, std::char_trais<CharT>>; mystring<char> str; // mystring就是化名

    noexcept

    void foo() noexcept; // void foo() noexcept(true);

    override

    用在虚函数身上,强制让函数签名完全相同。

    final

    用在2个地方:

    1. 告诉编译器这个类不能被继承。
    2. 告诉编译器这个函数不能override。

    Lambdas

    定义inline函数(仿函数、函数对象)。

    1. 方括号开始
    2. 括号表示变量
    3. 大括号是函数体

    简单的例子:

    []{std::out << "hello world" << std::endl;} // why not call it directly
    []{std::out << "hello lambda" << std::endl;}() // print lambda
    auto I = []{std::out << "hello lambda 2" << std::endl;} // 得到函数对象
    I(); // print lambda 2
    // 完整形式
    [...](...)mutable throwSpec -> retType {...}
    // mutable 关系到方括号内的数据是否可以被改写
    // 表示可以产生异常
    // 向右的箭头后面代表返回类型
    // 小括号里是参数
    // 中括号代表这是lambda函数开始
    // 中括号里面的内容
    // 如果 mutable、throwSpec和ret都不存在,那么括号可以不写。
    // 方括号[]内如果是=等号,就表示以值(而且是常量不能改变)的方式捕获外部变量;如果是&就表示以引用的方式捕获外部变量。
    // lambda的函数体必须不能太复杂,否则报错之后晦涩的错误信息将会极度地降低效率。
    

    Variadic Template

    例1:

    void printX() {}
    template<typename T, typename... Type>
    void printX(const T& firstArg, const Type&... args) 
    {
      cout << firstArg << endl; // 打印第一个参数
      printX(args...);  
    }
    printX(7.5,"hello",bitset<16>(377),42); // 此时如果执行这一行  
    // 就相当对第8行的print函数中的参数,逐一使用函数模板,结果就输出
    // 第8行函数中的所有参数
    

    例2:使用这个特性重写printf库函数。

    void printf(const char *s)
    {
      while (*s) {
        if (*s == '%' && *(s++) == '%') {
          throw std::runtime_error("invalid format string: missing");
        std::cout << *s++;
        }
      }
    }
    template<typename T, typename... Args>
    void printf(const char *s, T value, Args... args)
    {
      while (*s) {
        if (*s == '%' && *(s++) == '%') {
          std::cout << value;
          printf(++s, args...); // call even *s == 0
          return;
        }
      }
    }
    

    例3:实现maximun,一些值的最大值。

    注:用初始化列表也可以,所以只是实例,不是说这个例子是最佳实例。

    cout << max({1, 2, 3 4}) << endl;

    例4:实现maximun,一些值的最大值

    cout << maximum(57, 48, 60, 100, 20, 18) << endl;
    int maximum(int n) { return n; }
    template<typename... Args>
    int maximum(int n, Args... args)
    {
      return std::max(n, maximum(args...));
    }
    

    例5:使用类模板(用不同一般的方式使用first元素和last元素)

    。。。没看明白

    例6:用于递归继承的类模板

    template<typename... Values> class tuple;
    template<> class tuple<> {};
    ///////////////////////////////////////////
    template<typename Head, typename... Tail>
    class tuple<Head, Tail...> : private tuple<Tail...> 
    {
      typedef tuple<Tail...> inherited;
    protected:
      Head m_head; // 位置在head()函数必须要前面head()函数才能用成员变量m_head
    public:
      tuple(){}
      tuple(Head v, inherited(vtail...)):m_head(v), inherited(vtail..) {}
      
      // Head::type 编译不通过,不是所有类型都能::type
      // typename Head::type head() { return m_head; } 
      auto head()->decltype(m_head) { return m_head; }
      inherited& tail() { return *this; }
    }
    // run
    tuple<int, float, string> t(41, 6.3, "nico");
    cout << sizeof(t) << endl;
    cout << t.head() << endl;
    cout << t.tail().head() << endl;
    cout << t.tail().tail().head() << endl;
    // 结果是分行输出 41 6.3 nico
    

    例7:用于复合的递归

    和例6相似。

    右值引用

    新的类型,TR1后就有,但是大家不熟悉。

    用来避免一些不必要的copy。

    表达式都是右值,

    不能被做赋值操作的都是右值,例如a+1就是右值, 这个代码就是不成立的a+1=a。但是:

    string s1("aaa");
    string s2("bbb");
    s1 + s2 = s1; // just OK?!
    cout << s1 << endl <<  s2 << endl;
    string() = "ccc"; // OK too?!
    
    // try complex
    complex<int> c1(3, 8), c2(1, 0);
    c1 + c2 = complex<int>(41, 9); // c1 + c2 could be lvalue
    complex<int>() = complex<int>(3, 1); // ok too! temp obj could be assigned to sth!
    

    尽管如此,临时对象还是不能放在左边。

    待更新~

    痛苦苦苦苦苦苦苦苦苦并快乐着
  • 相关阅读:
    更新内核遇到 requested datatype primary not available
    在tmux缓冲区中搜索
    逻辑卷lvm消失问题.
    linux中的常用的proxy 代理方式
    windows下powershell的包管理工具
    一次docker镜像的迁移
    MAC OS 10.15 挂载ntfs文件系统并设置自动挂载RW模式.
    在linux中设置优先使用ipv4,而不是ipv6
    [搬家]新域名 akagi201.org
    基于Three.js的全景---photo-sphere-viewer
  • 原文地址:https://www.cnblogs.com/leoTsou/p/14952825.html
Copyright © 2020-2023  润新知