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;
}