c++11/14/17新特性

1. C++语言历程

C++语言从1983年正式诞生以来,经历了多次的修订与改版,主要从包含两个大的节点,一是1998年,C++语言正式被C++标准委员会纳入标准,二是2011年,C++语言新增了许多新的特性,大大提升C++语言的实用性。可以把C++标准分成两个大的版本,C++1.0(C++98,C++03,C++03(tr1))和C++2.0(C++11,C++14,C++17,C++20(草案))
在这里插入图片描述
C++1.0和2.0的主要特性

C++版本 特性
C++98 主要集成在兼容C特性的基础上增加面向对象的特性,包括类、简单继承、内联机制、函数默认参数以及强类型检查,虚函数、函数重载、引用机制(符号为&)、const关键字以及双斜线的单行注释,多重继承、保护成员以及静态成员等特性,并集成了标准模板库STL
C++03 主要修订C++98中存在的问题
C++03(tr1) 发布C++希望引入新特性的报告,但没有完全引入,后期加入部分std::tr1相关的功能
C++11 新增正则表达式(正则表达式详情)、完备的随机数生成函数库、新的时间相关函数,原子操作支持、标准线程库(2011之前,C和C++语言均缺少对线程的支持)、一种能够和某些语言中foreach语句达到相同效果的新的for语法、auto关键字、新的容器类、更好的union支持、数组初始化列表的支持以及变参模板的支持等等新特性
C++14 主要对C++11变准文案描述进行了修正
C++17 简化C++语言的日常使用
C++20

2. 各编译器对C++标准核心功能的支持

C++11核心功能 MSVC GCC ICC Clang 替代方案
Rvalue references 10.0 4.3 12.0 2.9 Boost.Move
Rvalue references for *this Nov 13 4.8.1 14.0 2.9
Initialization of class objects by rvalues 9.0 4.3 11.1 2.9
Non-static data member initializers 12.0 4.7 14.0 3.0
Variadic templates Nov 12 4.3 12.1 2.9
Extending variadic template template parameters Nov 12 4.4 12.1 2.9
Initializer lists Nov 12 4.4 14.0 3.1
Static assertions 10.0 4.3 11.1 2.9 Boost.StaticAssert
auto-typed variables 10.0 4.4 12.0 2.9 Boost.Typeof
Multi-declarator auto 10.0 4.4 12.0 2.9 Boost.Typeof
Removal of auto as a storage-class specifier 10.0 4.4 12.0 2.9 Boost.Typeof
New function declarator syntax 10.0 4.4 12.0 2.9 Boost.ReturnType
New wording for C++11 lambdas 10.0 4.5 12.0 3.1 Boost.Lambda
Declared type of an expression 10.0 4.3 12.0 2.9 Boost.Typeof
Incomplete return types 11.0 4.8.1 12.1 3.1
Right angle brackets 9.0 4.3 11.1 2.9 TR1
Default template arguments for function templates Nov 12 4.3 12.1 2.9
Solving the SFINAE problem for expressions No 4.4 12.1 2.9
Template aliases 12.0 4.7 12.1 3.0
Extern templates 9.0 4.3 11.1 2.9
Null pointer constant 10.0 4.6 12.1 3.0 自己实现的null_ptr
Strongly-typed enums 11.0 4.4 14.0 2.9 #define
Forward declarations for enums 11.0 4.6 14.0 3.1
Generalized attributes 14.0 4.8 12.1 3.3
Generalized constant expressions Nov 13 4.6 14.0 3.1
Alignment support Nov 13 4.8 No 3.3
Delegating constructors Nov 12 4.7 14.0 3.0
Inheriting constructors Nov 13 4.8 15.0 3.3
Explicit conversion operators Nov 12 4.5 14.0 3.0
New character types 14.0 4.4 14.0 2.9
Unicode string literals 14.0 4.5 14.0 3.0
Raw string literals Nov 12 4.5 14.0 3.0
Universal character name literals 14.0 4.5 12.1 3.1
User-defined literals VS14 CTP1 4.7 15.0 3.1
Standard Layout Types 11.0 4.5 No 3.0
Defaulted and deleted functions 12.0 4.4 12.0 3.0
Extended friend declarations 10.0 4.7 12.0 2.9
Extending sizeof Nov 13 4.4 14.0 3.1
Inline namespaces 14.0 4.4 14.0 2.9
Unrestricted unions 14.0 4.6 14.0 3.1
Local and unnamed types as template arguments 9.0 4.5 12.0 2.9
Range-based for 11.0 4.6 13.0 3.0 Boost.Foreach
Explicit virtual overrides 11.0 4.7 14.0 3.0 #define
Minimal support for garbage collection and reachability-based leak detection 10.0 No No No
Allowing move constructors to throw [noexcept] Nov 13 4.6 14.0 3.0
Defining move special member functions 14.0 4.6 14.0 3.0
Sequence points 12.0 4.8 15.0 3.3
Atomic operations 11.0 4.4 13.0 3.1 Boost.Atomic
Strong Compare and Exchange 11.0 4.8 13.0 3.1 Boost.Atomic
Bidirectional Fences 11.0 4.8 13.0 3.1 Boost.Atomic
Memory model 12.0 4.8 No 3.2 Boost.Atomic
Data-dependency ordering: atomics and memory model 11.0 4.8 No 3.2 Boost.Atomic
Propagating exceptions 10.0 4.4 12.0 2.9 Boost.Exception
Abandoning a process and at_quick_exit 14.0 4.8 No No
Allow atomics use in signal handlers 12.0 4.8 No 3.1
Thread-local storage 14.0 4.8 No 3.3 Boost.Thread
Dynamic initialization and destruction with concurrency Nov 13 4.8 No 2.9
func predefined identifier Nov 13 4.3 11.1 2.9 FUNCTION
C99 preprocessor No 4.3 11.1 2.9
long long 9.0 4.3 11.1 2.9 __int64
Extended integral types No No No No
C++14核心功能 MSVC GCC ICC Clang 替代方案
Tweak to certain C++ contextual conversions 12.0 4.9 16.0 3.4
Binary literals 14.0 4.9 11.0 2.9
Return type deduction for normal functions Nov 13 4.9 15.0 3.3
Generalized lambda capture (init-capture) 14.0 4.9 15.0 3.4
Generic (polymorphic) lambda expressions Nov 13 4.9 16.0 3.4
Variable templates 15.0 5.0 No 3.4
Relaxing requirements on constexpr functions 15.0 5.0 No 3.4
Member initializers and aggregates 15.0 5.0 16.0 3.3
Clarifying memory allocation No No No 3.4
Sized deallocation 14.0 5.0 17.0 3.4
[[deprecated]] attribute 14.0 4.9 16.0 3.4
Single-quotation-mark as a digit separator 14.0 4.9 16.0 3.4
C++17核心功能 MSVC GCC ICC Clang 替代方案
static_assert with no message 15.0 6 No 3.5 C++11’s static_assert
Disabling trigraph expansion by default 12.0 5.1 No 3.5
typename in a template template parameter 14.0 5 17.0 3.5
New auto rules for direct-list-initialization 14.0 5 17.0 3.8
Fold expressions No 6 No 3.6
Attributes for namespaces and enumerators 14.0 6 No 3.6
u8 character literals 14.0 6 17.0 3.6
Nested namespace definition 15.0 6 17.0 3.6
Allow constant evaluation for all non-type template arguments No 6 No 3.6
Remove deprecated register storage class No 7 No 3.8
Remove deprecated bool increment No 7 No 3.8
Make exception specifications part of the type system No 7 No No
__has_include in preprocessor conditionals No 5 No Yes
New specification for inheriting constructors (DR1941 et al) No 7 No 3.9
[[fallthrough]] attribute 15.0 7 No 3.9
[[nodiscard]] attribute No 7 No 3.9
[[maybe_unused]] attribute No 7 No 3.9
Aggregate initialization of classes with base classes No 7 No 3.9
constexpr lambda expressions No 7 No No
Unary Folds and Empty Parameter Packs No 6 No 3.9
Differing begin and end types in range-based for 15.0 6 No 3.9
Lambda capture of *this No 7 No 3.9
Direct-list-initialization of enums No 7 No 3.9
Hexadecimal floating-point literals No 3.0 No Yes
Using attribute namespaces without repetition No 7 No 3.9
Dynamic memory allocation for over-aligned data No 7 No No
Template argument deduction for class templates No 7 No No
Non-type template parameters with auto type No 7 No No
Guaranteed copy elision No 7 No No
Stricter expression evaluation order No 7 No No
Requirement to ignore unknown attributes No Yes No Yes
constexpr if-statements No 7 No 3.9
Inline variables No 7 No 3.9
Structured bindings No 7 No No
Separate variable and condition for if and switch No 7 No 3.9
Matching template template parameters to compatible arguments No 7 No No
Removing deprecated dynamic exception specifications No 7 No No
Pack expansions in using-declarations No No No No

3. c++11核心功能

3.1 可变参数模板(Variadic Template)

  • 主要增加关键字…, 表示一个组或者包,代表可变的参数个数或类型
  • 从模板函数上来看,可以更好的完成递归函数的调用,具体如代码example1
  • 从类模板的角度看,可以更方便的完成递归继承,具体如代码example2

example1 函数模板

//注意必须配一个无参的print函数,否则递归没有边界
void print()
{
}

//定义一个模板函数 1 + n, 更具化,
//(1)...                    表示一个所谓的包(pack),一组
//(2)typename... Types      模板参数包
//(3)const Types&... args   函数参数类型包
//(4)args...                参数包
template <typename T, typename... Types>
void print(const T& firstArg, const Types&... args)
{
    std::cout<<"i'm 1+n"<<std::endl;
    std::cout<<firstArg<<std::endl;
    //递归()
    print(args...);
}


//n  更泛化,优先调用更具化的模板函数
template <typename... Types>
void print(const Types&... args)
{
    std::cout<<"i'm n"<<std::endl;
    //递归
    print(args...);
}

example2 类模板

//注意,一定要先加这一句
template <typename... Values> class MytestClassTem;
template<> class MytestClassTem<>{};
template<typename First,typename... others>
class MytestClassTem<First, others...>
: private MytestClassTem<others...>
{
    typedef MytestClassTem<others...> inherited;
public:
    MytestClassTem(){}
    MytestClassTem(First v, others... args)
    :m_first(v), inherited(args...){}

    First first(){return m_first;}
    //此处返回的是父类的实例
    inherited& other(){return *this;}
protected:
    First m_first;
};


/调用
    MytestClassTem<int ,float,std::string> obj(41, 6.3, "hello");
    std::cout<<"子级:"<<obj.first()<<std::endl;
    std::cout<<"子级的上一级:"<<obj.other().first()<<std::endl;

3.2 右尖括号(Right Angle Brackets)

  • 在C++11之前,两个右尖括号之间必须加个空格
#include <vector>
typedef std::vector<std::vector<int> > Table;  // OK
typedef std::vector<std::vector<bool>> Flags;  // Error
  • C++ 11中,加或者不加空格,都可以识别了
#include <vector>
typedef std::vector<std::vector<int> > Table;  // OK
typedef std::vector<std::vector<bool>> Flags;  // OK

3.3 空指针(nullptr)

  • C++11之前没有关键字nullptr(其对应的类型为std::nullptr_t)
  • nullptr用于替换0或者NULL,因为NULL本身是定义为0的,有时候使用会产生歧义
    fun(0);//call fun(int)
    int i  = NULL;
    fun(i);//call fun(int)
    char* pp = NULL;
    fun(pp);//call fun(void*)
    fun(NULL);//有歧义
    fun(nullptr);//call fun(void*)

3.4 auto关键字

  • 在C++11中,可以auto定义变量,而不指定变量的类型
  • 编译器会从等号右边的表达式或变量来推断auto变量的类型
  • auto 一般用于替代变量类型名字太长,或表达式类型太复杂的场景
     //简单类型不建议使用auto
     auto data = 2;
    //typeid包含在#include <typeinfo>
    std::cout<<typeid(data).name()<<std::endl;//i --- int

    auto res = f();
    std::cout<<typeid(res).name()<<std::endl;//f  -- float

    
    //auto 一般用于替代变量类型名字太长,或表达式类型太复杂的场景
    std::vector<std::string> vecStr;
    auto itr = vecStr.begin(); //auto取代 std::vector<std::string>::iterator itr = vecStr.begin()
    auto lam = [](int x)->bool{return x = 0;}; // auto取代lambda表达式的类型

3.5 统一初始化(Uniform Initialization)

  • C++11之前,有三种为变量或对象初始化的方式,大括号,小括号, 赋值符号
  • C++ 11 引入统一的初始化方式 ————统一使用大括号,内部编译器会进行转换,编译器会在识别到{t1,t2,…,tn}时,自动保存至一个initializer_list对象中,并关联至一个一个array<T,n>,在调用构造函数时,会将array中的元素逐一分解传递给构造函数
  • 若构造函数的入参为initializer_list时,则不做分解,直接整包传进去
class TestInitializerList
{
public:
    TestInitializerList(int a, int b)
    {
        std::cout<<"TestInitializerList(int,int), a = "<<a<<",b="<<b<<std::endl;
    }

    
    TestInitializerList(std::initializer_list<int> initList)
    {
    
        std::cout<<"TestInitializerList(initializer_list<int> initList) ,vals = ";
        for(auto i : initList)
        {
            std::cout<<i<<",";
        
        }
        std::cout<<std::endl;
        
    }
};


    TestInitializerList a(77,5);//call TestInitializerList(int a, int b)
    TestInitializerList b{65,9};//若包含std::initializer_list<int>的构造函数存在,则调用,如不存在,则逐一分解,调用构造函数TestInitializerList(int a, int b)
    TestInitializerList c{34,56,78};若包含std::initializer_list<int>的构造函数存在,则调用,则分解,分解后若有匹配的构造函数则调用,没有匹配的会报错
    TestInitializerList d={67,90};//同d{65,9};

  • C++11也兼容之前的小括号和赋值符号的初始化方式
     before C++11
    //小括号
    Rect r(3,4);
    r.printRect();
    //大括号
    int ia[2] = {3,4};
    //赋值符号
    Rect r1 = {4,5};//在C++11之前只能使用构造函数来对对象初始化
    r1.printRect();

   //C++11 Uniform Initializzation
    int ib[2]{6,7};
    std::vector<int> vec{8,9};
    Rect r2{3,9};
    r2.printRect();
  • C++11引入统一的初始化对象或变量的方式,其主要目的是构造对象时可接收可变的参数,在标准库的设计上提供了很大的便利.
  • 引入了std::initializer_list<>模板类,其内部维护了一个std::array数据
    //有了Initializer List后,直接不限个数,#include<algorithm>
    std::cout<<std::max({1,2,3,4,5})<<std::endl;
    //有了Initializer List后,直接不限个数,#include<algorithm>
    std::cout<<std::min({1,2,3,4,5})<<std::endl;
  • {}可以为变量设定初值,但不能强制转换类型
int i;//i有一个未定义的值
   std::cout<<i<<std::endl;
   int j{};//j被初始化为0
   std::cout<<j<<std::endl;
   
   char* p;//p有一个未定义的指针值
   std::cout<<p<<std::endl;
   char* q{};//q=nullptr
   std::cout<<q<<std::endl;


    
   int i(5.3);//将浮点型强制转换成整型
   std::cout<<i<<std::endl;

   int j{5.0};//不会将浮点型强制转换成整型
   std::cout<<j<<std::endl;
   
   char p{8};//OK
   std::cout<<p<<std::endl;

   char q{99999};//99999不在char范围内,无法强制转换
   std::cout<<q<<std::endl;

3.6 关键字explicit

  • explicit含义是明确的,显示的,一般用在构造函数前面,但在C++11之前,只能放在包含一个入参的构造函数前面
struct TestExplicit
{
    explicit TestExplicit(int re, int im = 0):real(re),imag(im)
    {}
    
    TestExplicit operator+(const TestExplicit& x)
    {
    
        return TestExplicit((real+x.real),(imag+x.imag));
    }
    
    int real;
    int imag;

};


    TestExplicit a(12,5);
    std::cout<<a.real<<","<<a.imag<<std::endl;
    //编译器自动调用TestExplicit(int re, int im = 0)将int 5转换为TestExplicit对象
    //若加上explicit ,则调用TestExplicit(int re, int im = 0)时需要更加明确,不能默认将int 转换为则调用TestExplicit
    TestExplicit b = a + 5;
    std::cout<<b.real<<","<<b.imag<<std::endl;
  • C++11中允许explicit放在包含多个入参的构造函数前面(其实是基于Uniform Initialization,扩展了其功能)
class TestNewExplicit
{
public:
    TestNewExplicit(int a,int b)
    {
        std::cout<<"TestNewExplicit(int a,int b), a = "<<a<<",b="<<b<<std::endl;
    }
    
    TestNewExplicit(std::initializer_list<int> initList)
    {
        std::cout<<"TestNewExplicit(std::initializer_list<int> initList) ,vals = ";
        for(auto i : initList)
        {
            std::cout<<i<<",";
        
        }
        std::cout<<std::endl;
    }
    
    explicit TestNewExplicit(int a,int b,int c)
    {
        std::cout<<"explicit TestNewExplicit(int a,int b,int c), a = "<<a<<",b="<<b<<",c="<<c<<std::endl;
    }
    
    
};

    TestNewExplicit p1(77,5);
    TestNewExplicit p2{77,5};
    //TestNewExplicit p3{77,5,99,88};
    //若不存在接收std::initializer_list<int>参数的构造函数,则需要编译器自动分解,匹配个数进行调用相应参数的构造函数
    //若分解匹配后的构造函数前面加了explicit,则不能直接调用
    //converting to 'TestNewExplicit' from initializer list to TestNewExplicit
    TestNewExplicit p4 = {1,2,3};

3.7 基于范围的for循环(range-based for statement)

  • 从容器中依次取出元素进行处理
  • 接收者为引用时,则用一个指针指向容器中的元素,不需要拷贝一份
    for(int i : {1,2,3,4})
    {
        std::cout<<i<<std::endl;
    
    }
    
    std::vector<int> vec{4,5,6};
    for(auto& j : vec)
    {
        std::cout<<j<<std::endl;
        std::cout<<"j的地址:"<<&j<<",vec[0]的地址"<<&vec[0]<<std::endl;
    
    }

3.8 =default/=delete

  • Big-Three:表示类中默认的析构函数,拷贝构造函数,operator=(C++11中引入右值引用后,增加了移动拷贝构造函数,移动operator=, 被称为Big-Five),这些函数不能被重载
  • =default ,只能被用在Big-Five函数后面,表示使用编译器默认的函数
  • =delete, 一般用在Big-Five函数后面,但也可以使用在其他普通函数函数后面,表示告知编译器不要定义该函数(建议不要用在析构函数上)
class Test
{
public:
    //不能使用编译器默认的构造函数
    Test() = delete;

    Test(int a)
    {
        std::cout<<"Test(int a)"<<std::endl;
    }
};

class Zoo
{
public:
    //自定义构造函数
    Zoo(int i1,int i2):d1(i1),d2(i2)
    {}
    //拷贝构造函数,被删除
    Zoo(const Zoo&) = delete;
    //移动构造函数  使用编译器默认的
    Zoo(Zoo&&) = default;
    //赋值运算符   使用编译器默认的
    Zoo& operator=(const Zoo&) = default;
    //移动赋值运算符   被删除
    Zoo& operator=(const Zoo&&) = delete;
    virtual ~Zoo(){}
    
}

附:经典网站及书籍

名称 说明
C++14标准PDF https://doc.imzlp.me/viewer.html?file=docs/standard/isocpp2014.pdf
C++11标准PDF https://doc.imzlp.me/viewer.html?file=docs/standard/isoc11.pdf
多种编译器对C++11的支持 http://www.klayge.org/wiki/index.php/多种编译器对C%2B%2B11的支持
多种编译器对C++14的支持 http://www.klayge.org/wiki/index.php/多种编译器对C%2B%2B14的支持
多种编译器对C++17的支持 http://www.klayge.org/wiki/index.php/多种编译器对C%2B%2B17的支持
在线开发环境 https://wandbox.org/
各VS版本对C++11功能的支持 https://blog.csdn.net/xiaomu_347/article/details/82563688
侯捷老师的《C++11新特性》视频 https://www.bilibili.com/video/av51863195/?p=9

猜你喜欢

转载自blog.csdn.net/tianzhiyi1989sq/article/details/102648609