精华内容
参与话题
问答
  • C++17新特性个人总结

    万次阅读 多人点赞 2019-05-20 11:42:52
    C++17 1 关键字 1.1 constexpr 1.2 static_assert 1.3 auto 1.4 typename 1.5 inline 2 语法 2.1 折叠表达式 2.2 结构化绑定 2.3 允许非类型模板参数进行常量计算 2.4 条件分支语句初始化 2.5 聚合初始...

    目录

     

    C++17

    1 关键字

    1.1 constexpr

    1.2 static_assert

    1.3 auto

    1.4 typename

    1.5 inline

    2 语法

    2.1 折叠表达式

    2.2 结构化绑定

    2.3 允许非类型模板参数进行常量计算

    2.4 条件分支语句初始化

    2.5 聚合初始化

    2.6 嵌套命名空间

    2.7 lambda表达式捕获*this的值

    2.8 枚举[类]对象的构造

    2.9 十六进制单精度浮点数字面值

    2.10 基于对齐内存的动态内存分配

    2.11 细化表达式的计算顺序

    2.12 模板类的模板参数自动推导

    2.13 简化重复命名空间的属性列表

    2.14 不支持、非标准的属性

    2.15 改写与继承构造函数

    2.16 内联变量

    2.17 用auto作为非类型模板参数

    3 宏

    3.1 __has_include

    4 属性

    4.1 fallthrough

    4.2 nodiscard

    4.3 maybe_unuse

    结语


    C++17

    编译器版本:GCC 7.1、Clang 5.0

    __cplusplus:201703L

    编译选项:-std=c++17

    1 关键字

    1.1 constexpr

    扩展constexpr使用范围,可用于if语句中,也可用于lambda表达式中。

    例子1:

    #include<iostream>
    
    template<bool ok>
    constexpr void foo()
    {
        //在编译期进行判断,if和else语句不生成代码
        if constexpr (ok == true)
        {
            //当ok为true时,下面的else块不生成汇编代码
            std::cout << "ok" << std::endl;
        }
        else
        {
            //当ok为false时,上面的if块不生成汇编代码
            std::cout << "not ok" << std::endl;
        }
    }
    
    int main()
    {
        foo<true>();//输出ok,并且汇编代码中只有std::cout << "ok" << std::endl;这一句
        foo<false>();//输出not ok,并且汇编代码中只有std::cout << "not ok" << std::endl;这一句
        return 0;
    }
    

     

    例子2:

    int main()
    {
        constexpr auto add1 = [](int n, int m){
            auto func1 = [=] { return n; }; //func1  lambda表达式
            auto func2 = [=] { return m; }; //func2  lambda表达式
            return [=] { return func1() + func2(); };
        };
        constexpr auto add2 = [](int n, int m){
            return n + m;
        };
        auto add3 = [](int n, int m){
            return n + m;
        };
        int sum1 = add1(30, 40)( ); //传入常量值,add1在编译期计算,立即返回70
        int sum2 = add2(sum1, 4); //由于传入非constexpr变量,add2的constexpr失效,变成运行期lambda
        constexpr int sum3 = add3(1, 2); //sum3为constexpr变量,传入常量值,add3变成编译期lambda,立即返回3
        int sum4 = add2(10, 2);//传入常量值,add2在编译期计算,立即返回12
        return 0;
    }
    

     

    1.2 static_assert

    扩展static_assert用法,静态断言的显示文本可选。

    如:

    static_assert(true, "");
    static_assert(true);//c++17支持

     

    1.3 auto

    扩展auto的推断范围

    如:

    auto x1 = { 1, 2 }; //推断出std::initializer_list<int>类型
    auto x2 = { 1, 2.0 }; //错误:类型不统一,无法推断
    auto x3{ 1, 2 }; //错误:auto的聚合初始化只能一个元素
    auto x4 = { 3 }; //推断出std::initializer_list<int>类型
    auto x5{ 3 }; //推断出int类型
    

     

    1.4 typename

    扩展用法,允许出现在模板的模板的参数中。

    首先回顾一下typename的用法,①用于模板中,表示模板参数为类型;②用于声明某名字是变量名

    如例1:

    struct A
    {
        typedef int Example;
    };
    //第一种用法:声明模板参数为类型
    template<typename T>
    struct B { };
    
    struct C
    {
        typedef typename A::Example E;//第二种用法:声明某名字为一种类型
    };
    
    int main()
    {
        typename A::Example e;//第二种用法:声明某名字为一种类型
        return 0;
    }
    

    新特性下的typename用法,

    如例2:

    #include<iostream>
    #include<typeinfo>
    
    template<typename T>
    struct A
    {
        int num;
        A()
        {
            std::cout << "A Construct" << std::endl;
            std::cout << "template typename is: " << typeid (T).name() << std::endl;
        }
    };
    //此处的T可省略,X代表模板类型,T和X前的typename可替换成class
    template<template<typename T> typename X>
    struct B
    {
        X<double> e;
        B() { std::cout << "B Construct" << std::endl; }
    };
    
    int main()
    {
        A<B<A>> a;
        std::cout << "***************************" << std::endl;
        B<A> b;
        return 0;
    }
    

    运行结果:

     

    1.5 inline

    扩展用法,可用于定义内联变量,功能与内联函数相似。inline可避免函数或变量多重定义的问题,如果已定义相同的函数或变量(且该函数或变量声明为inline),编译器会自动链接到该函数或变量。

    如(不发生错误):

    //  test.h
    inline void print()
    {
        std::cout << "hello world" << std::endl;
    }
     
    inline int num = 0;
    //  func.h
    include "test.h"
    inline void add(int arg)
    {
        num += arg;
        print();
    }
    //  main.cpp
    include "func.h"
    int main()
    {
        num = 0;
        print();
        add(10);
        return 0;
    }
    

     

    2 语法

    2.1 折叠表达式

    用于变长参数模板的解包,只支持各种运算符(和操作符),分左、右折叠

    如:

    #include<string>
    
    template<typename ... T>
    auto sum(T ... arg)
    {
        return (arg + ...);//右折叠
    }
    
    template<typename ... T>
    double sum_strong(T ... arg)
    {
        return (arg + ... + 0);//右折叠
    }
    
    template<typename ... T>
    double sub1(T ... arg)
    {
        return (arg - ...);//右折叠
    }
    
    template<typename ... T>
    double sub2(T ... arg)
    {
        return (... - arg);//左折叠
    }
    
    int main()
    {
        int s1 = sum(1, 2, 2, 4, 5);//解包:((((1+)2+)3+)4+)5 = 15
        double s2 = sum(1.1, 2.2, 3.3, 4.4, 5.5, 6.6);
        double s3 = sum(1, 2.2, 3, 4.4, 5);
    
        double s4 = sub1(5, 2, 1, 1);//解包:((((5-)2-)1-)1) = 1
        double s5 = sub2(5, 2, 1, 1);//解包:(5-(2-(1-(1)))) = 3
    
        double s6 = sum_strong();//s6 = 0
    
        std::string str1("he");
        std::string str2("ll");
        std::string str3("o ");
        std::string str4("world");
        std::string str5 = sum(str1, str2, str3, str4);//str5 = "hello world"
        return 0;
    }
    

     

    2.2 结构化绑定

    用一对包含一个或多个变量的中括号,表示结构化绑定,但是使用结构化绑定时,须用auto关键字,即绑定时声明变量

    例子1:

    /*
     * 例子:多值返回
     */
    struct S
    {
        double num1;
        long num2;
    };
    
    S foo(int arg1, double arg2)
    {
        double result1 = arg1 * arg2;
        long result2 = arg2 / arg1;
        return {result1, result2};//返回结构体S对象
    };
    
    int main()
    {
        auto [num1, num2] = foo(10, 20.2);//自动推导num1为double,num2为long
        return 0;
    }
    

    例子2:

    #include<list>
    #include<map>
    
    /*
     * 例子:循环遍历
     */
    template<typename T, typename U>
    struct MyStruct
    {
        T key;
        U value;
    };
    
    int main()
    {
        std::list<MyStruct<int, double>> Container1;
        std::map<int, MyStruct<long long, char>> Container2;
        for(auto [key, value] : Container1)
        {
            //key为int类型,value为double类型
        }
        for(auto [key, value] : Container2)
        {
            //key为int类型,value为MyStruct<long long, char>类型
            //value1为long long类型,value2为char类型
            auto [value1, value2] = value;
        }
        return 0;
    }
    

    2.3 允许非类型模板参数进行常量计算

    非类型模板参数可传入类的静态成员

    如:

    class MyClass
    {
    public:
        static int a;
    };
    
    template<int *arg>
    void foo() {}
    
    int main()
    {
        foo<&MyClass::a>();
        return 0;
    }
    

    2.4 条件分支语句初始化

    在if和switch中可进行初始化

    如:

    template<long value>
    void foo(int &ok)
    {
        if constexpr (ok = 10; value > 0)
        {
    
        }
    }
    
    int main()
    {
        int num = 0;
        if(int i = 0; i == 0)
        {
    
        }
        foo<10>(num);
        switch(int k = 10; k)
        {
            case 0:break;
            case 1:break;
            default:break;
        }
        return 0;
    }
    

     

    2.5 聚合初始化

    在初始化对象时,可用花括号进行对其成员进行赋值

    如:

    struct MyStruct1
    {
        int a;
        int b;
    };
    
    struct MyStruct2
    {
        int a;
        MyStruct1 ms;
    };
    
    int main()
    {
        MyStruct1 a{10};
        MyStruct2 b{10, 20};
        MyStruct2 c{1, {}};
        MyStruct2 d{{}, {}};
        MyStruct2 e{{}, {1, 2}};
        return 0;
    }
    

     

    2.6 嵌套命名空间

    简化多层命名空间的写法

    如:

    //传统写法
    namespace A
    {
        namespace B
        {
            namespace C
            {
    
            };
        };
    };
    //新写法
    namespace A::B::C
    {
    
    };
    

    2.7 lambda表达式捕获*this的值

    lambda表达式可捕获*this的值,但this及其成员为只读

    如:

    struct MyStruct {
        double ohseven = 100.7;
        auto f() {
            return [this] {
                return [*this] {
                    this->ohseven = 200.2;//错误,只读变量不可赋值
                    return ohseven;//正确
                };
            }();
        }
        auto g() {
            return []{
                return [*this]{};//错误,外层lambda表达式没有捕获this
            }();
        }
    };
    

    2.8 枚举[类]对象的构造

    可以给枚举[类]对象赋值

    如:

    enum MyEnum { value };
    MyEnum me {10};//错误:不能用int右值初始化MyEnum类型对象
    
    enum byte : unsigned char { };
    byte b { 42 }; //正确
    byte c = { 42 }; //错误:不能用int右值初始化byte类型对象
    byte d = byte{ 42 }; //正确,其值与b相等
    byte e { -1 }; //错误:常量表达式-1不能缩小范围为byte类型
    
    struct A { byte b; };
    A a1 = { { 42 } }; //错误:不能用int右值初始化byte类型对象
    A a2 = { byte{ 42 } }; //正确
    
    void f(byte);
    f({ 42 }); //错误:无类型说明符
    
    enum class Handle : unsigned int { value = 0 };
    Handle h { 42 }; //正确
    

    2.9 十六进制单精度浮点数字面值

    以0x前缀开头的十六进制数,以f后缀的单精度浮点数,合并,就有了十六进制的单精度浮点数

    如:

    int main()
    {
        float value = 0x1111f;
        return 0;
    }
    

     

    2.10 基于对齐内存的动态内存分配

    谈到动态内存分配,少不了new和delete运算符,新标准中的new和delete运算符新增了按照对齐内存值来分配、释放内存空间的功能(即一个新的带对齐内存值的new、delete运算符重载)

    函数原型:

    void* operator new(std::size_t size, std::align_val_t alignment);
    void* operator new[](std::size_t size, std::align_val_t alignment);
        
    void operator delete(void*, std::size_t size, std::align_val_t alignment);
    void operator delete[](void*, std::size_t size, std::align_val_t alignment);
    

    参数说明:

    size —— 分配的字节数。必须为alignment的整数倍。

    alignment —— 指定的对齐内存值。必须是实现支持的合法对齐。

     

    new的返回值:

    成功,返回指向新分配内存起始地址的指针。

     

    用法例子:

    #include<new>
    
    struct alignas(8) A {};
    
    int main()
    {
        A *a = static_cast<A *>(::operator new(sizeof(A), static_cast<std::align_val_t>(alignof (A))));
        ::operator delete(a, sizeof(A), static_cast<std::align_val_t>(alignof (A)));
        return 0;
    }
    

    2.11 细化表达式的计算顺序

    为了支持泛型编程和重载运算符的广泛使用,新特性将计算顺序进行的细化

    如以下争议代码段:

    #include<map>
    
    int main()
    {
        std::map<int, int> tmp;
        //对于std::map的[]运算符重载函数,在使用[]新增key时,std::map就已经插入了一个新的键值对
        tmp[0] = tmp.size();//此处不知道插入的是{0, 0}还是{0, 1}
        return 0;
    }
    

    为了解决该情况,新计算顺序规则为:

    ①后缀表达式从左到右求值。这包括函数调用和成员选择表达式。

    ②赋值表达式从右向左求值。这包括复合赋值。

    ③从左到右计算移位操作符的操作数。

     

    2.12 模板类的模板参数自动推导

    定义模板类的对象时,可以不指定模板参数,但必须要在构造函数中能推导出模板参数

    如:

    template<class T> struct A {
        explicit A(const T&, ...) noexcept {} // #1
        A(T&&, ...){} // #2
    };
    
    int i;
    
    A a1 = { i, i }; //错误,不能根据#1推导为右值引用,也不能通过#1实现复制初始化
    A a2{i, i}; //正确,调用#1初始化成功,a2推导为A<int>类型
    A a3{0, i}; //正确,调用#2初始化成功,a2推导为A<int>类型
    A a4 = {0, i}; //正确,调用#2初始化成功,a2推导为A<int>类型
    
    template<class T> A(const T&, const T&) -> A<T&>; // #3
    template<class T> explicit A(T&&, T&&) -> A<T>; // #4
    
    A a5 = {0, 1}; //错误,#1和#2构造函数结果相同(即冲突)。根据#3推导为A<int&>类型
    A a6{0, 1}; //正确,通过#2推断为A<int>类型
    A a7 = {0, i}; //错误,不能将非静态左值引用绑定到右值。根据#3推导为A<int&>类型
    A a8{0, i}; //错误,不能将非静态左值引用绑定到右值。根据#3推导为A<int&>类型
    
    template<class T> 
    struct B {
    
        template<class U> 
        using TA = T;//定义别名
    
        template<class U> 
        B(U, TA<U>);//构造函数
    };
    
    B b{(int*)0, (char*)0}; //正确,推导为B<char *>类型
    

    2.13 简化重复命名空间的属性列表

    如:

    [[ using CC: opt(1), debug ]] void f() {}
    //作用相同于 [[ CC::opt(1), CC::debug ]] void f() {}
    

    2.14 不支持、非标准的属性

    在添加属性列表时,编译器会忽略不支持的非标准的属性,不会发出警告和错误。

     

    2.15 改写与继承构造函数

    在类的继承体系中,构造函数的自动调用是一个令人头疼的问题。新特性引入继承与改写构造函数的用法。

    例子1:

    #include<iostream>
    
    struct B1
    {
        B1(int) { std::cout << "B1" << std::endl; }
    };
    
    struct D1 : B1 {
        using B1::B1;//表示继承B1的构造函数
    };
    
    D1 d1(0);    //正确,委托基类构造函数进行初始化,调用B1::B1(int)
    

    例子2:

    #include<iostream>
    
    struct B1
    {
        B1(int) { std::cout << "B1" << std::endl; }
    };
    
    struct B2
    {
        B2(int) { std::cout << "B2" << std::endl; }
    };
    
    struct D1 : B1, B2 {
        using B1::B1;//表示继承B1的构造函数
        using B2::B2;//表示继承B2的构造函数
    };
    D1 d1(0);    //错误:函数冲突,
    
    struct D2 : B1, B2
    {
        using B1::B1;
        using B2::B2;
        //正确,D2::D2(int)隐藏了B1::B1(int)和B2::B2(int)。另外由于B1和B2没有默认的构造函数,因此必须显式调用B1和B2的构造函数
        D2(int) : B1(1), B2(0)
        { std::cout << "D2" << std::endl; }
    };
    
    struct D3 : B1 
    {
        using B1::B1;
    };
    D3 d3(0);//正确,继承B1的构造函数,即利用B1的构造函数来初始化,输出B1
    
    // 程序入口
    int main()
    {
        D2 d(100);//编译通过,输出B1   B2   D2
        return 0;
    }
    

    例子3:

    #include<iostream>
    
    struct B1
    {
        B1() { std::cout << "B1 default" << std::endl; }
        B1(int) { std::cout << "B1" << std::endl; }
    };
    
    struct B2
    {
        B2() { std::cout << "B2 default" << std::endl; }
        B2(int) { std::cout << "B2" << std::endl; }
    };
    
    struct D1 : B1, B2
    {
        using B1::B1;
        using B2::B2;
        //正确,D2::D2(int)隐藏了B1::B1(int)和B2::B2(int),但必须要显示调用B1和B2的构造函数
        D1(int) : B1(1), B2(0)
        { std::cout << "D2" << std::endl; }
        //有默认构造函数,在不显示调用基类的构造函数时自动调用基类的默认构造函数
        D1()  { std::cout << "D2 default" << std::endl; }
    };
    // 程序入口
    int main()
    {
        D1 d(100);//编译通过,输出B1   B2   D2
        D1 dd;
        //输出
        //B1 default
        //B2 default
        //D2 default
        return 0;
    }
    

    2.16 内联变量

    见1.5

     

    2.17 用auto作为非类型模板参数

    当模板参数为非类型时,可用auto自动推导类型

    如:

    #include<iostream>
    
    template<auto T>
    void foo()
    {
        std::cout << T << std::endl;
    }
    
    int main()
    {
        foo<100>();//输出100
        foo<int>();//no matching function for call to "foo<int>()"
        return 0;
    }
    

     

    3 宏

    3.1 __has_include

    判断有没有包含某文件

    如:

    int main()
    {
    #if __has_include(<cstdio>)
        printf("hehe");
    #endif
    #if __has_include("iostream")
        std::cout << "hehe" << std::endl;
    #endif
    return 0;
    }
    

    4 属性

    4.1 fallthrough

    用于switch语句块内,表示会执行下一个case或default

    如:

    int main()
    {
        int ok1, ok2;
        switch (0)
        {
            case 0:
            ok1 = 0;
            [[fallthrough]];
            case 1:
            ok2 = 1;
            [[fallthrough]];
        }
        return 0;
    }
    

    4.2 nodiscard

    可用于类声明、函数声明、枚举声明中,表示函数的返回值没有被接收,在编译时会出现警告。

    如:

    [[nodiscard]] class A {}; //该属性在这其实没用
    [[nodiscard]] enum class B {}; //该属性在这其实没用
    class C {};
    
    [[nodiscard]] int foo()
    { return 10; }
    
    [[nodiscard]] A func1() { return A(); }
    [[nodiscard]] B func2() { return B(); }
    [[nodiscard]] C func3() { return C(); }
    
    int main()
    {
        foo();//warning: ignoring return value
        func1();//warning: ignoring return value
        func2();//warning: ignoring return value
        func3();//warning: ignoring return value
        return 0;
    }
    

    4.3 maybe_unused

    可用于类、typedef、变量、非静态数据成员、函数、枚举或枚举值中。用于抑制编译器对没用实体的警告。即加上该属性后,对某一实体不会发出“没有用”的警告。

    用法例子:

    [[maybe_unused]] class A {};
    [[maybe_unused]] enum B {};
    [[maybe_unused]] int C;
    [[maybe_unused]] void fun();
    

    结语

    本次检验C++17新特性使用了GCC编译器,对于Clang的支持性方面没有做出差异测试。若有问题,欢迎指出

    展开全文
  • 基于 C++ 11,C++ 17 旨在使 C++ 成为一个不那么臃肿复杂的编程语言,以简化该语言的日常使用,使开发者可以更简单地编写和维护代码。 C++ 17 是对 C++ 语言的重大更新,引入了许多新的语言特性: UTF-8 ...

    昨日,ISO C++ 委员会正式发布了 C++ 17 标准,正式名称为 ISO/IEC 14882:2017。

    基于 C++ 11,C++ 17 旨在使 C++ 成为一个不那么臃肿复杂的编程语言,以简化该语言的日常使用,使开发者可以更简单地编写和维护代码。

    C++ 17 是对 C++ 语言的重大更新,引入了许多新的语言特性:

    • UTF-8 字符文字

    • 折叠表达式 (fold expressions):用于可变的模板

    • 内联变量 (inline variables):允许在头文件中定义变量

    • 在 if 和 switch 语句内可以初始化变量

    • 结构化绑定 (Structured Binding):for (auto [key,value] : my_map) {…}

    • 类模板参数规约 (Class Template Argument Deduction):用 pair p{1, 2.0}; 替代 pair<int, double>{1, 2.0};

    此外,C++ 17 还带来了并行 STL,派生自 Boost 的文件系统库等其他特性。

    作为标准库中新的关键“词汇类型”,std::string_view 和 std::optional 将会以函数参数和返回类型的形式广泛使用。这允许开发者编写更简单的签名,例如:在字符串类型上可以用 std::string_view 替代模板化 (Templatizing);开发者可在函数体内更多地用 std::variant 和 std::any 类型作为类成员,并内部使用。

    我们也曾报道过 C++ 17 的一些新特性,具体内容可点此查看

    LLVM 的 Clang 编译器也已经将代码中出现“C++1z”的地方修改为“C++17”(C++ 17 曾被称为 C++1z)。GCC 和 LLVM/Clang 都有效地提供了完整的 C++ 17 支持。

    对于正在进行中的 C++ 20,预计在两年内( 2019 年夏天)完成所有功能。

    ps:小编迫切求涨粉。。。


    展开全文
  • 了解如何使用更新的c++ 17语言进行编程。您将从基础知识开始,并通过一步一步的例子逐步成为一名工作的c++程序员。您只需要开始使用c++ 17和任何最新的c++编译器,您很快就会编写真正的c++程序。没有预先编程知识的...
  • C++17 是继 C++14 之后,C++ 编程语言 ISO/IEC 标准的下一次修订的非正式名称。而就在昨日,ISO C++ 委员会正式发布了 C++ 17 标准,官方名称为 ISO/IEC 14882:2017。 C++ 17 标准化图表 C ++ 17 主要

    点击上方“CSDN”,选择“置顶公众号”

    关键时刻,第一时间送达!

    何为 C++ 17?

    C++17 是继 C++14 之后,C++ 编程语言 ISO/IEC 标准的下一次修订的非正式名称。而就在昨日,ISO C++ 委员会正式发布了 C++ 17 标准,官方名称为 ISO/IEC 14882:2017。

    640?wx_fmt=png&wxfrom=5&wx_lazy=1

    C++ 17 标准化图表

    640?wx_fmt=png&wxfrom=5&wx_lazy=1

    C ++ 17 主要特性

    基于 C++ 11,C++ 17 旨在使 C++ 成为一个不那么臃肿复杂的编程语言,以简化该语言的日常使用,使开发者可以更简单地编写和维护代码。

    C++ 17 是对 C++ 语言的重大更新,引入了许多新的语言特性:

    • UTF-8 字符文字;

    • 折叠表达式 (fold expressions):用于可变的模板;

    • 内联变量 (inline variables):允许在头文件中定义变量;

    • 在 if 和 switch 语句内可以初始化变量;

    • 结构化绑定 (Structured Binding):for (auto [key,value] : my_map) {…};

    • 类模板参数规约 (Class Template Argument Deduction):用 pair p{1, 2.0}; 替代 pair<int, double>{1, 2.0};;

    更多的特性还有:

    • 使 static_assert 的文本信息可选;

    • 删除 trigraphs;

    • 在模板参数中允许使用 typename(作为替代类);

    • 来自 braced-init-list 的新规则用于自动推导;

    • 嵌套命名空间的定义,例如:使用 namespace X::Y { … } 代替 namespace X { namespace Y { … }};

    • 允许命名空间和枚举器的属性;

    • 新的标准属性:[[fallthrough]], [[maybe_unused]] 和 [[nodiscard]];

    • 对所有非类型模板参数进行常量评估;

    • Fold 表达式,用于可变的模板;

    • A compile-time static if with the form if constexpr(expression);

    • 结构化的绑定声明,现在允许 auto [a, b] = getTwoReturnValues();

    • 在某些情况下,确保通过编译器进行 copy elision(Guaranteed copy elision by compilers in some cases);

    • 一些用于对齐内存分配的扩展;

    • 构造函数的模板推导,允许使用 std::pair(5.0, false) 代替 std::pair<double,bool>(5.0, false);

    • __has_include,允许由预处理程序指令检查头文件的可用性;

    • __cplusplus 的值更改为 201703L;

    此外,C++ 17 还带来了并行 STL,派生自 Boost 的文件系统库等其他特性。

    作为标准库中新的关键“词汇类型”,std::string_view 和 std::optional 将会以函数参数和返回类型的形式广泛使用。这允许开发者编写更简单的签名,例如:在字符串类型上可以用 std::string_view 替代模板化 (Templatizing);开发者可在函数体内更多地用 std::variant 和 std::any 类型作为类成员,并内部使用。

    LLVM 的 Clang 编译器也已经将代码中出现“C++1z”的地方修改为“C++17”(C++ 17 曾被称为 C++1z)。GCC 和 LLVM/Clang 都有效地提供了完整的 C++ 17 支持。

    0?wx_fmt=png

    对于正在进行中的 C++ 20,预计在两年内( 2019 年夏天)完成所有功能。

    更多 ISO/IEC 14882:2017 内容可参考:https://www.iso.org/standard/68564.html

    640?wx_fmt=jpeg640?wx_fmt=png

    0?wx_fmt=gif

    展开全文
  • C++17新属性详解

    万次阅读 多人点赞 2018-05-27 21:59:38
    C++17的入选特性有:(1).非类型模板参数的 auto 模板参数分为两种,一种是类型模板参数,也是我们用得最多的一种:template &lt;typename T, typename U&gt; auto add(T t, U u) { return t+u; } 里面的...

          C++迭代速度相对来说还是比较慢的,2010年以后,C++的新版本迭代速度有所加快,这一点,从C++标准版本的历史发布图1就可以看出来:

                                 

                                                      图1 C++正式版本发布历史

         C++11算是更新比较大的一次了,引入了很多新属性,以至于C++11出来以后,好多C++同行感叹,这看了C++11感觉像是在学习一门新语言!哈哈,这可能跟C++属性众多和库众多有关吧。现在我们来看看C++17的新增属性吧。

         C++17的入选特性有:

    (1).非类型模板参数的 auto

          模板参数分为两种,一种是类型模板参数,也是我们用得最多的一种:

    template <typename T, typename U>
    auto add(T t, U u) {
        return t+u;
    }

         里面的 T 和 U 都是类型模板参数。另一种是非类型模板参数,它可以让不同的字面量成为模板的参数:

    template <typename T, int BufSize>
    class buffer_t {
    public:
        T& alloc();
        void free(T& item);
    private:
        T data[BufSize];
    }
    
    buffer_t<int, 100> buf; // 100 作为模板参数

           遗憾的是我们在编写模板的时候就必须明确非类型模板参数的具体类型,C++17 打破了这一限制,让我们能够在非类型模板参数中使用 auto 关键字,从而让编译器推导具体的类型:

    template <auto value> void foo() {
        return;
    }
    
    foo<10>();  // value 被推导为 int 类型

    (2).std::variant<>

           熟悉 boost 的人应该很早就听说过 variant<> 了。variant<> 可以用于存储和操作不同类型的对象。我们在前面(对标准库的扩充:新增容器)对于迭代 std::tuple 时,简单使用了 boost::variant<>。提供给 variant<> 的类型模板参数可以让一个 variant<> 从而容纳提供的几种类型的变量(在其他语言(例如 Python/JavaScript 等)表现为动态类型)。

           C++17 正式将 variant<> 纳入标准库,摇身一变成为 std::variant<>,有了它之后,我们可以将前面的代码更改为:

    #include <variant>
    template <size_t n, typename... Args>
    std::variant<Args...> _tuple_index(size_t i, const std::tuple<Args...>& tpl) {
        if (i == n)
            return std::get<n>(tpl);
        else if (n == sizeof...(Args) - 1)
            throw std::out_of_range("越界.");
        else
            return _tuple_index<(n < sizeof...(Args)-1 ? n+1 : 0)>(i, tpl);
    }
    template <typename... Args>
    std::variant<Args...> tuple_index(size_t i, const std::tuple<Args...>& tpl) {
        return _tuple_index<0>(i, tpl);
    }

    (3).结构化绑定(Structured bindings)

           结构化绑定提供了类似其他语言中提供的多返回值的功能。到目前为止,我们可以通过 std::tuple 来构造一个元组,囊括多个返回值。但缺陷是显而易见的,我们没有一种简单的方法直接从元组中拿到并定义元组中的元素,尽管我们可以使用 std::tie 对元组进行拆包,但我们依然必须非常清楚这个元组包含多少个对象,各个对象是什么类型。

          C++17 给出的结构化绑定可以让我们写出这样的代码:

    std::tuple<int,double,std::string> f() {
        return std::make_tuple(1,2.3,"456");
    }
    auto [x,y,z] = f(); // x,y,z 分别被推导为int,double,std::string

    (4).变量声明的强化

          变量的声明在虽然能够位于任何位置,甚至于 for 语句内能够声明一个临时变量 int,但始终没有办法在 if 和 switch语句中声明一个临时的变量。例如:

    auto p = map_container.try_emplace(key, value);
    if(!p.second) {
        //...
    } else {
        //...
    }
    

    C++17 消除了这一限制,使得我们可以:

    if (auto p = m.try_emplace(key, value); !p.second) {   
        //...
    } else {
        //...
    }

    C++17未入选特性有:

    (1).Concepts

          C++ 组委会在讨论投票最终确定 C++17 有很多提案,诸如 Concepts/Ranges/Module 等等,其中最受关注的就是 Concepts,可惜这一提案最终被拒,作为技术规范(Technical Specifications, TS) 将其发布。

          Concepts 是对 C++ 模板编程的进一步增强扩展。简单来说,Concepts 是一种编译期的特性,它能够让编译器在编译期时对模板参数进行判断,从而大幅度增强我们在 C++ 中模板编程的体验。使用模板进行编程时候我们经常会遇到各种令人发指的错误,这是因为到目前为止我们始终不能够对模板参数进行检查与限制,例如下面简单的两行代码会造成大量的几乎不可读的编译错误:

    #include <list>
    #include <algorithm>
    int main() {
        std::list<int> l = {1, 2, 3};
        std::sort(l.begin(), l.end());
        return 0;
    }

          而这段代码出现错误的根本原因在于,std::sort 对排序容器必须提供随机迭代器,否则就不能使用,而我们知道 std::list 是不支持随机访问的。用 Concepts 的话来说就是:std::list中的迭代器不满足std::sort中随机迭代器这个 Concepts(概念) 的 requirements(要求)。有了 Concepts,我们就可以这样:

    template <typename T> 
    requires Sortable<T>    // Sortable 是一个 concept
    void sort(T& c);

       缩写为:

    template<Sortable T>    // T 是一个 Sortable 的类型名
    void sort(T& c)

    甚至于直接将其作为类型来使用:

    void sort(Sortable& c); // c 是一个 Sortable 类型的对象
           遗憾的是,C++组委会没有将 Concetps 纳入新标准,而是将其作为TS正式发布(其实早在 C++11 最终定案之前就已经有 Concepts 的呼声了,但 Concepts TS 是2015年才完整正式发布),也就是我们现在看到的 Concepts TS。C++组委会拒绝将 Concepts 纳入新标准的原因其实很简单,并不是技术层面上的原因,纯粹是觉得它还不够成熟。

           Concepts TS 的发布到最后一次 C++17 的讨论会只相隔了不到四个月的时间,Concepts 的(唯一)实现只存在于一个未发布的 gcc 版本中。而 gcc 中关于 Concepts 的实现就是由撰写 Concepts TS 的人开发的,虽然它能够进行相关测试,但还没有认真讨论过这份 TS 会产生哪些不良后果,更何况这份 TS 都没有被测试过。此外,已知的 Concepts 的一个明显的作用就是去辅助实现 Ranges TS 等提案,但实际上它们也没有被选入 C++17,所以可以把 Concepts 继续延后。

            总的来说,类似于 Concepts/Ranges/Modules 这些令人兴奋的特性并没有入选至 C++17,这注定了 C++17 某种意义上来说相较于 C++11/14 依然只是小幅度更新,但我们有望在 C++2x 中看到这些东西的出现。

       C++11/14/17对C++编译器的支持情况:

    http://en.cppreference.com/w/cpp/compiler_support

    展开全文
  • C++17 filesystem 文件系统(详解)

    万次阅读 2019-06-10 21:04:15
    本文主要介绍C++17中的filesystem中的一些常用方法 一、C++17的支持 https://blog.csdn.net/qq_40946921/article/details/90645890 二、头文件及命名空间 #include<filesystem> using namespace std::...
  • C++11/14/17-实验楼笔记

    千次阅读 2019-02-28 20:45:27
    目录 环境准备 被弃用的特性 常量字符串赋值需要使用const char* 与C的兼容性 语言可用性的强化 类型推导 区间迭代 列表初始化 模板增强 面对对象增强 语言运行期的强化 Lambda表达式 ...std:...
  • C++11 & C++14 & C++17新特性

    千次阅读 2018-08-17 12:01:24
    https://www.cnblogs.com/guxuanqing/p/6707824.html
  • C++11 & C++14 & C++17新特性

    千次阅读 2019-08-25 16:37:51
    C++11:C++11包括大量的新特性:包括lambda表达式,类型推导关键字auto、decltype,和模板的大量改进。 新的关键字 auto C++11中引入auto第一种作用是为了自动类型推导 auto的自动类型推导,用于从初始化表达式...
  • C++17之 Inline变量

    千次阅读 2019-08-27 22:00:56
    c++的一个优点是它支持只使用头文件库的开发。然而,c++ 17之前,头文件中不需要或不提供全局变量或对象时才有可能成为一个库。c++ 17可以在头文件中定义一个内联的变量/对象,如果这个定义被... // OK since C++17...
  • 2017年底,C++17标准正式颁布,该标准的最大贡献是,提供了STL库算法的并行运算版本,对于我这种喜欢追求算法性能的程序员而言,无疑是一个极大的福音。幸运地是,Linux系统标准编译器GCC能完美地支持C++ 17标准,但...
  • [译]C++17,标准库新引入的并行算法

    千次阅读 2018-09-15 14:32:02
    看到一个介绍 C++17 的系列博文(原文),有十来篇的样子,觉得挺好,看看有时间能不能都简单翻译一下,这是第七篇~ C++17 对 STL 算法的改动,概念上其实很简单.标准库之前有超过100个算法,内容包括搜索,计数,区间及...
  • [译]C++17,标准库有哪些新变化?

    千次阅读 2018-08-18 14:38:21
    看到一个介绍 C++17 的系列博文(原文),有十来篇的样子,觉得挺好,看看有时间能不能都简单翻译一下,这是第二篇~ C++17 有许多新的标准库变化,简单起见,这篇文章只介绍了以下内容:std::string_view,标准模板库中新...
  • C++17中那些值得关注的特性(上)

    千次阅读 2017-07-28 09:25:06
    作者:祁宇,《深入应用C++11》作者,C++开源社区purecpp.org创始人,...C++17标准在2017上半年已经讨论确定,正在形成ISO标准文档,今年晚些时候会正式发布。本文将介绍最新标准中值得开发者关注的新特新和基本用法...
  • 详解C++17线程池的实现

    千次阅读 2019-03-30 02:43:42
    C++标准库在C++11之后新增了线程特性,C++的线程在此之后可以进行跨平台使用。在其他的OOP语言(例如Java、C#等)中有线程池...本文将用C++17实现一个简单的线程池,github地址:https://github.com/Invictus2/Thread...
  • 这个表格主要为C++中的关键字和操作符替代名!!来自《C++ primer 》5Th! c++关键字分类: 数据类型:void,int,char,float,double,bool,w_char 类型定义:struct,union,enum,class,typedef 常量值...
  • 作者 | 祁宇责编 | 郭芮出品 | CSDN(ID:CSDNnews)不断出现的C++新的标准,正在改变元编程的编程思想,新的idea和方法不断涌现,让元编程变得越来越...
  • C++C++ 17简单上手(1)

    千次阅读 2018-06-26 19:24:43
    C++ 17标准已经发布了有一段时间了(甚至于后一个版本C++ 20也在路上了),最近终于得空(懒癌治愈),查阅了相关资料,简单上手一下。简单的感受,一个是“现代”C++和C语言确实已经是天差地别,另一个就是标准库中...
  • C++11 & C++14 & C++17新特性

    千次阅读 2018-12-06 07:59:13
    C++11:C++11包括大量的新特性:包括lambda表达式,类型推导关键字auto、decltype,和模板的大量改进。 新的关键字 auto C++11中引入auto第一种作用是为了自动类型推导 auto的自动类型推导,用于从初始化表达式...
  • C++17标准STL库并行策略在GCC编译器中的替代实现方法 一、引言 C++ 17标准中一个令人兴奋的特性是对STL库中的69个算法加入了执行策略(execution policies),允许在少量修改的情形下,对原有STL库算法实现并行...

空空如也

1 2 3 4 5 ... 20
收藏数 283,307
精华内容 113,322
关键字:

c++17

c++ 订阅