c++ 11 14 17 20后的新特性总结(持续更新)

  • Post author:
  • Post category:其他


c++ 11 14 17 20后的新特性

c++11

1.auto

auto 不能用于函数传参、auto 还不能用于推导数组类型

2.lambda:匿名函数、闭包(闭包就是能够读取其他函数内部变量的函数-定义在一个函数内部的函数)

Lambda 表达式的基本语法如下:

[捕获列表](参数列表) mutable(可选) 异常属性-> 返回类型{
// 函数体
}

3.右值引用

c++14

4.结构化绑定

5.std::thread

6.std::regex

7.concept

8.nullptr

取代NULL,NULL为0,而非(void *)0:

std::is_same<decltype(NULL), decltype(0)>::value
if(std::is_same<decltype(NULL), decltype(0)>::value)
        cout<<"NULL == 0"<<endl;

9.decltype

#include <type_traits>

计算某个表达式的类型

10.std::is_same

11.constexpr(c++14 可以在内部使用局部变量、循环和分支等简单语句;c++11不可以)

从C++14 开始,constexpr 函数可以在内部使用局部变量、循环和分支等简单语句,例如下面的代

码在C++11 的标准下是不能够通过编译的:

constexpr int fibonacci(const int n) {
	if(n == 1) return 1;
	if(n == 2) return 1;
	return fibonacci(n-1) + fibonacci(n-2);
	}
c++11使用方式:
constexpr int fibonacci(const int n) {
	return n == 1 || n == 2 ? 1 : fibonacci(n-1) + fibonacci(n-2);
	}

c++17

12.if和switch中可以定义临时变量

// 将临时变量放到if 语句内
if (const std::vector<int>::iterator itr = std::find(vec.begin(), vec.end(), 3);
itr != vec.end()) 
{
*itr = 4;
}

13.std::initializer_list初始化列表

#include <initializer_list>

c++17

14.结构化绑定——元组:std::tuple、std::get、std::tie

#include <tuple>

c++14

15.尾返回值自动推导

//auto尾返回类型
template<class T, class U>
auto Calculate_end(T t, U u)->decltype(t+u)
{
    return t+u;
}

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

16.嵌套依赖型——模板使用class与typename的区别

template<typename X>
void constructFun()
{
    typename X::const_iterator *x;
}

c++14

17.decltype(auto)使用

decltype(auto) 主要用于对转发函数或封装的返回类型进行推导,它使我们无需显式的

指定decltype 的参数表达式

decltype(auto) pack_sdkFun()
{
    return sdkFun();
}

18.if constexpr :编译时完成分支判断,c++17

template<typename T>
auto print_type_info(const T& t)
{
    if constexpr(std::is_integral<T>::value)
    {
        return t+1;
    }
    else
    {
        return t+0.2;
    }
}

19.for区间迭代

 for(auto tr : vec)
        cout<<"区间迭代"<<tr<<endl;

20.模板——类型别名表示(using)

 typedef void (*pFuncb)();
    using newpFun = void (*)();
    template<typename T>
    using TmplMagicType = MagicFoo<T>;

21.外部模板/’>’;

template class std::vector<vector<int>>;//强制实例化
extern template class std::vector<double>;//编译时不在该文件中实例化

22.默认模板参数

template<class T=int, class U=float>
auto Calculate_default(T t, U u)
{
    return t+u;
}
    cout<<"默认模板参数;"<<Calculate_default(5, 6.6)<<endl;

23.变参模板

//类
template<typename... Args>
class Variable
{
public:
    Variable(Args... args)
    {
        cout<<sizeof...(args)<<endl;
    }
};

//函数
template<typename... Args>
void variableFun(Args... args)
{
    cout<<sizeof...(args)<<endl;
}

Variable<int,int,float>(1,2,'c');
Variable<std::string>("str");
variableFun("123",1);

24.显示虚函数重载:override与final

override 当重载虚函数时,引入override 关键字将显式的告知编译器进行重载,编译器将检查基函

数是否存在这样的虚函数,否则将无法通过编译:

final 则是为了防止类被继续继承以及终止虚函数继续重载引入的。

25.显示禁用默认构造函数

class Default
{
public:
    Default() = default;//显示声明使用编译器生成的构造函数
    Default& operator=(const Default &def) = delete;//显示紧张编译器生成拷贝构造函数
};

26.强类型枚举(定义一种新类型)

enum class new_enum:unsigned int
{
    type1 = 0,
    type2 = 1,
    type3 = 1,
};

enum class new_enum1
{
    type1 = 1,
    type2,
    type3,
};
//if(new_enum::type2 == new_enum1::type1)
        //cout<<"enum type is not same"<<endl;
 //cout<<new_enum1::type1<<endl;

    if(new_enum::type3 == new_enum::type2)
        cout<<"enum type is same"<<endl;

27.左值/右值引用与lambda

//右值引用:T &&,其中T 是类型。

    auto important = std::make_unique<int>(2);
    auto add = [v1=1,v2=std::move(important)](int x, int y){
        return x+y+v1+(*v2);
    };
    //std::move();//转换右值
    //std::forward();//完美转发,就是为了让我们在传递参数的时候,保持原来的参数类型(左引用保持左引用,右引用保持右引用)
    cout<<add(3,4)<<endl;

    string strl = "zyc";
    string &&strr = std::move(strl);//string &&strr = strl;右值引用不能引用左值
    const string &strl1 = strl+strl;//string &strl1 = strl+strl;非常量左值引用不能引用左值
    strr += " test";
    cout<<strr<<endl;

class A
{
public:
    int *pointer;
    A():pointer(new int(1)){
        cout<<"构造"<<pointer<<endl;
    }

    A(A &a):pointer(new int(*a.pointer)){
        cout<<"拷贝"<<pointer<<endl;
    }

    A(A&& a):pointer(a.pointer){
        a.pointer = nullptr;
        cout<<"移动"<<pointer<<endl;
    }

    ~A(){
        cout<<"析构"<<pointer<<endl;
        delete pointer;
    }

};

    A obj;
    *obj.pointer = 3;
    cout<<obj.pointer<<endl;
    cout<<*obj.pointer<<endl;
    A objb(obj);//拷贝构造
    A objc(std::move(obj));//右值引用构造
    obj.~A();//析构
    *objb.pointer = 4;
    *objc.pointer = 5;
    cout<<*objb.pointer<<endl;
    cout<<*objc.pointer<<endl;

28.智能指针

#include <memory>

29.std::function、std::bind、std::placeholders

#include <functional>
    std::function<float(int,float,int)> FunF = [&](int x, float y, int z)->float{return x+y+z;};
    auto FunB = std::bind(FunF, std::placeholders::_1, 1.2, 3);
    cout<<FunB(10)<<endl;

总结:

1.模板定义全部使用typename替代class

2.子类继承虚函数后,全部加override;不提供对外继承的类全部加final;

3.左值引用必须加const:const T& t;右值引用——“移动”方法,解决“拷贝”问题;

4.尽量使用(#include )std::lock_guardstd::mutex mtx(m)替代(#include )std::mutex;使用std::unique_lock替代std::lock_guard;

5.使用不带参数构造函数构造对象时,优先使用不带括号形式,因为带括号(既可以是一个对象,又可以是函数声明),c++编译器优先认为是一个函数声明;

LL:

#include <mutex>
//std::lock_guard
class lock_thread final:public thread
{
public:
    void start_test(int num)
    {
        std::lock_guard<std::mutex> lock(m_mtx);
        cout<<"start "<<num<<endl;
        std::this_thread::sleep_for(chrono::seconds(5));
    }
private:
    std::mutex m_mtx;

};

void lock_guard_test()
{
    lock_thread lthread;//lock_thread lthread();报错——因为不带参数的构造函数,比如lthread()它可以是一个对象,也可是一个函数声明。但是c++编译器总是优先认为是一个函数声明,然后是对象。
    lthread.start_test(3);
    lthread.start_test(6);
    lthread.join();
}

示例应用程序:

#include <iostream>
#include <type_traits>
#include <vector>
#include <algorithm>
#include <initializer_list>
#include <tuple>
#include <random>
#include <utility>
#include <memory>
#include <functional>

using namespace std;

template<typename T>
class MagicFoo
{
public:
   MagicFoo(std::initializer_list<int> list){
        for(auto it=list.begin(); it!=list.end(); ++it)
            m_vec.emplace_back(*it);
   }

   void PrintVec(){
       for(auto it=m_vec.begin(); it!=m_vec.end(); ++it)
           cout<<*it<<endl;
   }
private:
   std::vector<int> m_vec;


};

void foo(char *p)
{
    cout<<"foo(char *) is called"<<endl;
}

void foo(int num)
{
    cout<<"foo(int) is called"<<endl;
}

#define __over_cpp 1
//斐波纳契--递归处理
constexpr int fibonacci(const int n)
{
#ifdef __over_cpp
    if(n == 1) return 1;
    if(n == 2) return 1;
    return fibonacci(n-1) + fibonacci(n-2);
#else//__c++11
    return n==1 || n==2 ? 1:fibonacci(n-1)+fibonacci(n-2);
#endif
}

constexpr int constexpr_foo(int n)
{
    return n+3;
}

std::tuple<int, double, std::string> tupleFoo()
{
    return std::make_tuple(3, 4.2, "zyc");
}

template<class R, class T, class U>
R Calculate(T t, U u)
{
    return t+u;
}

//auto尾返回类型
template<class T, class U>
auto Calculate_end(T t, U u)->decltype(t+u)
{
    return t+u;
}

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

template<class T=int, class U=float>
auto Calculate_default(T t, U u)
{
    return t+u;
}

//9.嵌套依赖型——模板使用class与typename的区别
template<typename X>
void constructFun()
{
    typename X::const_iterator *x;
}

//9.decltype(auto)
char sdkFun()
{
    int a=10;
    return a;
}

decltype(auto) pack_sdkFun()
{
    return sdkFun();
}

/*
 *
 * 10.if constexpr :编译时完成分支判断,c++17
template<typename T>
auto print_type_info(const T& t)
{
    if constexpr(std::is_integral<T>::value)
    {
        return t+1;
    }
    else
    {
        return t+0.2;
    }
}
*/

//12.外部模板/'>';
template class std::vector<vector<int>>;//强制实例化
extern template class std::vector<double>;//编译时不在该文件中实例化

template<typename T>
using TmplMagicType = MagicFoo<T>;

//15.变参模板
//类
template<typename... Args>
class Variable
{
public:
    Variable(Args... args)
    {
        cout<<sizeof...(args)<<endl;
    }
};

//函数
template<typename... Args>
void variableFun(Args... args)
{
    cout<<sizeof...(args)<<endl;
}

//16.变参模板展开
/*
template<typename T, typename ... Args>
void variableList(T t, Args ... args)
{
    cout<<t<<endl;
    (void)std::initializer_list<T>{([&args]{
            std::cout<<args<<endl;
    }(),t)...};
}
*/

//17.override/final
class Base{
    virtual void foo() final;
    virtual void foo1();
};

class Base1 final:public Base
{
    virtual void foo1() override;

};

/*Base1 final继承
class Base2:public Base1
{

};
*/

class Base3:public Base
{
    //void foo();Base::foo() final继承
};

//18.显示禁用默认构造函数
class Default
{
public:
    Default() = default;//显示声明使用编译器生成的构造函数
    Default& operator=(const Default &def) = delete;//显示紧张编译器生成拷贝构造函数
};

//19.强类型枚举(定义一种新类型)
enum class new_enum:unsigned int
{
    type1 = 0,
    type2 = 1,
    type3 = 1,
};

enum class new_enum1
{
    type1 = 1,
    type2,
    type3,
};

/*
template<typename T>
std::ostream& operator <<(typename std::enable_if<std::is_enum<T>::value, std::ostream>::type& stream)
{
    return stream<<static_cast<typename std::underlying_type<T>::type>(e);
}
*/

//20.右值引用
class A
{
public:
    int *pointer;
    A():pointer(new int(1)){
        cout<<"构造"<<pointer<<endl;
    }

    A(A &a):pointer(new int(*a.pointer)){
        cout<<"拷贝"<<pointer<<endl;
    }

    A(A&& a):pointer(a.pointer){
        a.pointer = nullptr;
        cout<<"移动"<<pointer<<endl;
    }

    ~A(){
        cout<<"析构"<<pointer<<endl;
        delete pointer;
    }

};

int main(int argc, char *argv[])
{
    //1.nullptr与NULL
    if(std::is_same<decltype(NULL), decltype(0)>::value)
        cout<<"NULL == 0"<<endl;
    //7.decltype
    if(std::is_same<decltype(NULL), decltype((void *)0)>::value)
        cout<<"NULL == (void *)0"<<endl;

    if(std::is_same<decltype(NULL), decltype(nullptr)>::value)
        cout<<"NULL == nullptr"<<endl;

    foo(NULL);
    foo(0);
    foo(nullptr);

    cout<<fibonacci(11)<<endl;
    //2.常量表达式-constexpr
    int array[constexpr_foo(6)];
    cout<<sizeof(array)/sizeof(int)<<endl;

    //int a =8;
    //int array_const[a];
    vector<int> vec={1,2,3,4};

    vector<int>::iterator it=find(vec.begin(),vec.end(),2);
    if(it!=vec.end())
        *it = 3;

/*3.if/switch中定义临时变量
    if (auto num = foo(); num & 0x01)
        cout << "The " << num << " is singular.";
    else
        cout << "The " << num << " is even.";
*/

    //11.for区间迭代
    for(auto &tr : vec)
    {
        cout<<"区间迭代"<<tr<<endl;
        tr += 1;
    }

    //6.auto
    for(auto itr=vec.begin(); itr != vec.end();++itr)
    {
        cout<<*itr<<endl;
    }

    //4.初始化列表(构造函数、普通函数)
    MagicFoo<int> magicFoo{3,5,8,11};
    //MagicFoo magicFoo = {3,5,8,11};
    magicFoo.PrintVec();

    //5.结构化绑定
    auto xp = tupleFoo();

    int a;double b;std::string c;
    std::tie(a,b,c) = xp;
    cout<<a<<b<<c<<endl;

    //8.auto尾返回类型推导
    decltype(Calculate_end<int, float>(5, 6.7)) n = Calculate<float,int,float>(2, 5.6);
    cout<<n<<endl;

    auto w = Calculate_simple<float, int>(8.8, 10);
    if(std::is_same<decltype(w), float>::value)
    {
        cout<<"is same type"<<endl;
    }

    //13.模板——类型别名表示(using)
    typedef void (*pFuncb)();
    using newpFun = void (*)();

    //14.默认模板参数
    cout<<"默认模板参数;"<<Calculate_default(5, 6.6)<<endl;

    //15.
    Variable<int,int,float>(1,2,'c');
    Variable<std::string>("str");
    variableFun("123",1);

    //16.可变参模板:初始化列表+lambda表达式
    //variableList(3,'c',8,"test");

    //19
    //if(new_enum::type2 == new_enum1::type1)
        //cout<<"enum type is not same"<<endl;
    //cout<<new_enum1::type1<<endl;

    if(new_enum::type3 == new_enum::type2)
        cout<<"enum type is same"<<endl;

    //20.左值/右值与lambda
    //右值引用:T &&,其中T 是类型。
    auto important = std::make_unique<int>(2);
    auto add = [v1=1,v2=std::move(important)](int x, int y){
        return x+y+v1+(*v2);
    };
    //std::move();//转换右值
    //std::forward();//完美转发,就是为了让我们在传递参数的时候,保持原来的参数类型(左引用保持左引用,右引用保持右引用)
    cout<<add(3,4)<<endl;

    string strl = "zyc";
    string &&strr = std::move(strl);//string &&strr = strl;右值引用不能引用左值
    const string &strl1 = strl+strl;//string &strl1 = strl+strl;非常量左值引用不能引用左值
    strr += " test";
    cout<<strr<<endl;

    A obj;
    *obj.pointer = 3;
    cout<<obj.pointer<<endl;
    cout<<*obj.pointer<<endl;
    A objb(obj);//拷贝构造
    A objc(std::move(obj));//右值引用构造
    obj.~A();//析构
    *objb.pointer = 4;
    *objc.pointer = 5;
    cout<<*objb.pointer<<endl;
    cout<<*objc.pointer<<endl;

    //21.std::function、std::bind、std::placeholders
    std::function<float(int,float,int)> FunF = [&](int x, float y, int z){return x+y+z;};
    auto FunB = std::bind(FunF, std::placeholders::_1, 1.2, 3);
    cout<<FunB(10)<<endl;

    return 0;
}



版权声明:本文为weixin_43246024原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。