导图社区 cPlusPlus 11和14
自己整理C++11和14的重点:当调用到P p1={11,12,13}时编译器会报错,因为等于号为赋值操作等号右边编译器会隐式转换 拆分initializer_list为特化函数优先调用而 P p2{11,12,13} 编译器通过 因为:{11,12,13}类型为编译器指定的initializer_list,直接调用初始化。
编辑于2022-06-22 08:47:45自己整理C++11和14的重点:当调用到P p1={11,12,13}时编译器会报错,因为等于号为赋值操作等号右边编译器会隐式转换 拆分initializer_list为特化函数优先调用而 P p2{11,12,13} 编译器通过 因为:{11,12,13}类型为编译器指定的initializer_list,直接调用初始化。
自己整理的c 11和14 主要信息深度解读,包括:模板类templates引入、大挂号初始化、initializer_list)explicit加入多个初始化函数支持、for (decl : coll) { statement }、=default,=delete、模板化名using。
社区模板帮助中心,点此进入>>
自己整理C++11和14的重点:当调用到P p1={11,12,13}时编译器会报错,因为等于号为赋值操作等号右边编译器会隐式转换 拆分initializer_list为特化函数优先调用而 P p2{11,12,13} 编译器通过 因为:{11,12,13}类型为编译器指定的initializer_list,直接调用初始化。
自己整理的c 11和14 主要信息深度解读,包括:模板类templates引入、大挂号初始化、initializer_list)explicit加入多个初始化函数支持、for (decl : coll) { statement }、=default,=delete、模板化名using。
c++ 11和14
模板类templates引入...
泛化是指参数类型不定(template类型),特化是指参数类型一定(例如:int、string等)
定义:创建typename... Types 作为参数定义:const Types&... args 作为参数:args... 元素个数:sizeof...(args) 重点补充:最后一定再写一个args...为空时的函数或类结尾
template <typename T,typename... Types> void print(const T& firstArg,const Types&... args){ cout << firstArg <<sizeof... (args); print(args...); } 函数1 void print() //用于结尾,必须写参数为空情况,否则死循环 { cout <<endl;//用于结尾 }函数2
模板函数调用优先级:特化 > 泛化 当查找到传入参数有相应特定函数时,优先调用 例如:template<typename... Types> void print(const Types&... args) { } 函数3 和函数1和函数2同时存在时,编译会通过,但函数2永远不会被调用,因为 特化 优先于 泛化
例子1:求一个类型里最大值 int maxNum(int n){ return n; } template<typename... Args> int maxNum(int n,Args... args){ return max(n,maxNum(args...)); } 使用:cout << maxNum( 11,50,17,80,4,16,) <<endl; 结果:80
例子2:模板参数,解析出头尾并打印出 目标:cout<<make_tuple( 7.5,string("hello"),1150)<<endl; 结果打印为:[7.5,"hello",1150]; template<typename.. Args>//sizeof...(Args)用于解析元素个数,作为最大值 ostream& operator<<(ostream& os,const tuple<Args...>& t ){ os<<"["; PRINT_TUPLE<0,sizeof...(Args),Args...>::print(os,t); return os<<"]" } template<int IDX,int MAX,typename... Args> struct PRINT_TUPLE{ static void print(ostream& os,const tuple<Args...>& t) { os << get< IDX >( t ) <<( IDX+1 == MAX ? "" : "," ); PRINT_TUPLE<IDX+1,MAX,Args...>::print( os , t ); } } template<int MAX,typename... Args> //用于结尾接收最大值退出递归 struct PRINT_TUPLE<MAX,MAX,Args...>{ static void print(ostream& os,const tuple<Args...>& t){ } }
例子3:用于递归继承,震惊!!!!! template<typename.. Values> class tuple; template<> class tuple<>{ } 最顶部继承基类 template<typename Head,typename... Tail> class tuple<Head, Tail...> : private tuple<Tail...> { typedef tuple<Tail...> inherited;//上一级继承类别名 public: tuple( ){ } tuple( Head v, Tail... vtail) : m_head(v),inherited( vtail... ) //绑定上一级继承类对象{ } Head head(){ return m_head;} inherited& tail() { return *this; } //返回上一级继承类的对象 protected: Head m_head; } 使用:tuple<int, float, string> t( 41,6.3,"hello" ); cout << sizeof(t) <<endl; // 结果: 12 cout << t.head() <<endl; // 结果:41 cout << t.tail().head() << endl; // 结果:6.3 cout << t.tail().tail().head() << endl; // 结果:hello
大挂号初始化(initializer_list)
基本用法
int* p{} 等价于 int* p = nullptr
int p{} 定价与 int p = 0
p(int a,int b)中 调用1:p(11,6); 调用2:P{33,7};
初始化数组等容器 list<int> p{11,32}
底层代码由initializer_list 实现,默认赋值如 = 为浅拷贝 指向同一块地址
拓展用法
min(),max()支持大括号初始化 所以支持任意多的数比较大小, 如 min({11,12,16,18,19}) 结果为11
explicit加入多个初始化函数支持
例如:class P { public: P(int a,int b){} P(initializer_list<int>){} explicit P(int a,int b,int c){} }
当调用到P p1={11,12,13}时编译器会报错,因为等于号为赋值操作 等号右边编译器会隐式转换 拆分initializer_list为特化函数优先调用 而 P p2{11,12,13} 编译器通过 因为:{11,12,13}类型为 编译器指定的initializer_list,直接调用初始化
for(decl : coll){ statement }
例如:for( int i : { 2,2,2,6,4,8,7,55,6 } ){ count << i <<endl; }
vector<double> ver; for( auto elem : vec ){// elem 拷贝 vec 里元素迭代器 速度慢 cout << elem <<endl; //只是读 } for( auto &elem : vec){//elem 直接引用vec 里元素迭代器 速度快 elem *=3;//此时为改变容器里每个数都乘以3 }
小插曲 begin() , end()是c++ 11特有的全局函数,支持容器 例如:begin(vec) ,end(ver) 应用有待考证,没有使用成功
=default,=delete
=default 就是定义了构造函数,但还是要编译器默认的构造空函数 例如:class P{ public: P(int i){}//如果没有P()=defalut编译器不会构造默认的构造函数P() P()=defalut;//通知编译器构造一个默认构造函数 } 有关编译器自动生成的默认构造函数 例如:定义一个空类 class Fun1{} 编译器会自动生成默认函数, 以下函数都可以用=defalut 来通知编译器帮你自动生成 class Fun{ Fun( ) {} //支持=defalut Fun(const Fun&rhs){...} //支持=defalut ~Fun(){...} //支持=defalut Fun& operator=(const Fun& rhs){} //支持=defalut };
=delete 单例里禁止赋值函数 也可以用于继承后,弃用基类的对应函数 例如:void isEmpty()=delete;意为弃用isEmpty函数
using化名使用
模板化名
定义例子:template <typename T> using Vec = std::vector<T,MyAlloc<T>> 使用例子:Vec<int> coll 有别于#define 全文替换
例子1: template<typename T> using Vec = std::vector<T,allocator<T>>; template<typename Container> void test_debug_head_end(Container continer){ qDebug()<<*(continer.begin())<<*(--continer.end()); } 使用:test_moveable<Vec<int>>({18,12,13});
函数化名
例子2: 以前:typedef void (*func)(int,int) 现在:using func = void(*)(int,int) void example(int,int){} func fn = example;
例子3:用于类里别名 template<typename T> struct Container{ using value_type = T;//代替typedef } template<typename Cntr> void fn2(const Cntr& c) { typename Cntr::value_type n; }
历史使用打开命名空间
例如:using namespace std //打开std命名空间 using std:count //打开std部分命名空间
noexcept(表示此处异常处理了)
异常解释:函数出现异常会一直往上层抛异常,直到被上层处理为止 ,如果到最上层都没有处理异常,则直接调用std::terminate(),然后 默认执行std::abort() 函数 程序就崩溃并关闭了
小知识补充:std::vector容器有别于其他容器,且具有成长性,会大量搬动内存位置 如果自定义类型 move函数中没有noexcept,则vector会报错因为vector担心搬动过程中出现异常无法处理
override(继承基类函数检查)
主要用于函数继承虚函数时,加入override,编译器会帮助你查找继承的基类函数是否存在 例如:void fun()override;
final(表示此函数或类不支持继承)
例子: struct Base1 final {} struct Der1 :Base1 {}//会报错
例子2: struct Base2 { virtual void f()final; } struct Base3:Base2 { void f();//会报错 }
decltype(用个类型 表示一个表达式 ,相当于typeof)通知编译器反推类型
例子1: template<typename T1,typename T2> auto add(T1 x,T2 y) -> decltype(x+y) ; decltype(x+y) 表示x+y返回后的任意类型,如int,string,等 类似于lambdas语法:[...](...)mutable throwSpec -> retType{...}
例子2:反推内部模板参数类型 template<typename T> void test_decltype(T obj){ typedef typename decltype(obj)::iterator iType 代替:typedef typename T::iterator iType }
例子3:反推lambda函数类型 auto cmp = [](const Person& p1,const Person& p2){ return p1.lastname()<p2.lastname(); } ... std::set<Person,decltype(cmp)> coll(cmp)
小知识补充:模板类只是半成品,编译虽然通过,但使用时编译器生成可能会报错
lambdas [...](...)mutable throwSpec -> retType{...}
符号解析
[ ] 获取外部参数 特殊表示如下 [ this ] 以值的形式捕获this指针 [ = ] 以值的形式捕获所有外部变量 [ & ] 以引用形式捕获所有外部变量 [ =, &x ] 变量x以引用形式捕获,其余变量以传值形式捕获 [ &, x ] 变量x以值的形式捕获,其余变量以引用形式捕获 例: int b=2; [ b ](...){ ... } 例2: [ &b ](...){ b++;... } 例3: [ this ](...){ this->xxx ; ... } ...
( ) 函数参数 例: [ ](int a,int b ){ ...}
mutable 指使用外部参数, 且供lambdas函数内修改, 相当于编译器会自动生成一个匿名类 使用时必须加 ( ) 例:[ id ]( ) mutable{ id++;... } 相当于编译器自动生成一个匿名类 class Functor{ private: int id;//使用mutable 时 外部id copy到这定义 public: void operator() (){ //运算符重载一个() id++;//函数内容在这里面调用 ... } } 错误写法:[ id ]( ){ id++;... } //会报错不能改变id值
throwSpec 表示抛出异常 使用时必须加 ( ) 例: auto fe = [id](int a,int b) throw ( int,exception,...) { throw 100; ... }; try { f(11,12); } catch (...) { //...参数为任意异常并非省略号 cout<<"error xxx"<<endl; }
retType 是描述返回类型 使用时必须加() 例:[ ]( )->int{ ...;return 11; }
例子1:最简写法 定义:auto f = []{ ... }; 使用:f();
例子2: vector<int> vi{5,28,50,60,70,83,90}; int x =30; int y =70; vi.erase( remove_if( vi.begin(),vi.end(), //以下为lambdas写的范围定义 [x,y](int n){ return x<n && n<y; } ),vi.end() ); for(auto i : vi ){ cout<<i<<" "; //5 28 83 90 } cout<<endl;
高阶例子: auto cmp = [](const T& p1,const T& p2){ return p1<p2; } ... std:set<T,decltype(cmp)> coll(cmp);//如果看不懂看set容器标准库源码
小知识补充:lambdas没有默认构造函数,也没有默认赋值操作
白色:次要
绿色:一般
橙色:重要