- 变长参数实例 __VA_ARGS__ 替换省略号代表的字符串
#define LOG(...){\ fprintf(stderr,"File: %s ,Func: %s ,Line: %d\t",__FILE__,__FUNCTION__,__LINE__);\ fprintf(stderr,__VA_ARGS__);\ fprintf(stderr,"\n");\ } //Test LOG("Msg:%s", "I am error");
- 断言assert
断言是在运行期进行验证,适用于Debug调试使用
assert(sizeof(int) == 8);
- 静态断言
编译阶段就可以验证
//static_assert(sizeof(int) == 8, "This is Error!"); static_assert(sizeof(int) == 4, "64-bit code generation is not supported.");
- #error
#error需要和ifdef 配合使用,判断某些特定条件
#ifdef _COMMPP std::cout << "all right!" << std::endl; #else //#error "this is error"; #endif
- noexcept修饰符与noexcept操作符
方法一,仅添加一个noexcept修饰符,在抛出异常时,调用std::terminate中断程序执行,noexcept默认为noexcept(true)
比基于异常机制的throw()在效率上会高一些。这是因为异常机制会带来一些额外开销。void func_no_exce() noexcept; void class::func_no_exce() noexcept { throw 1; } //Test try { log.func_no_exce(); //不抛异常 } catch (...) { std::cout << "func_no_exce!\n"; }
方法二,添加一个noexcept修饰符和常量表达式(值为true,说明不会抛出异常;反之,则可能会抛出异常),在抛出异常时,调用std::terminate中断程序执行
void func_no_exce(int val) noexcept(false); void class::func_no_exce(int val) noexcept(false) { throw 1; } //Test try { log.func_no_exce(0); //抛出异常,被catch捕获 } catch (...) { std::cout << "func_no_exce!\n"; }
- noexcept作为操作符
noexcept(expression),noexcept操作符不对expression求值。
若expression含有至少一个下列潜在求值的构造则结果为false。
[a] 调用没有指定不抛出异常的任意类型函数,除非它是常量表达式。
[b] throw表达式。
[c] 目标类型是引用类型,且转换时需要运行时检查的dynamic_cast表达式。
[d] 参数类型是多态类类型的typeid表达式。void test() { } void test_noexcept() noexcept(true) { } void test_noexcept_false() noexcept(false) { } cout << noexcept(test()) << endl; // false cout << noexcept(test_noexcept()) << endl; // true cout << noexcept(test_noexcept_false()) << endl; // false cout << noexcept(throw) << endl; // false
- noexcept做操作符,应用于模板
该函数是否是一个noexcept的函数取决于T()是否会抛出异常,第二个noexcept就是一个noexcept操作符,当其参数是一个有可能抛出异常的表达式的时候,其返回值为false,反之为true。
template
void fun_template()noexcept(noexcept(T())) { throw 1; } class Base { public: void f() {} }; class Log :public Base { public: Log() {} //noexcept做模板 ~Log() noexcept(false) { } void fun_test_template(); }; void Log::fun_test_template() { cout << noexcept(Log()) << endl; cout << noexcept(Base1()) << endl; try { fun_template (); } catch (...) { cout << "throw fun_template Log" << endl; throw } try { fun_template (); // terminate } catch (...) { cout << "throw fun_template Base1" << endl; } } class Base1 :public Base { public: ~Base1()noexcept(true) { } }; //Test log.fun_test_template();
- 快速初始化成员变量
“就地”声明:支持在类声明的时候使用等号"="初始化类中静态成员变量,这种声明方式我们称之为“就地”声明
C++98要求静态成员必须满足常量性,而且类型必须是整型或者枚举型,而非静态成员变量的初始化则必须在构造函数中进行。在C++11中,允许使用 等号= 或者 花括号{} 进行就地的非静态成员变量初始化。
初始化列表的效果总是优先于就地初始化。
//快速初始化成员变量 class InitVal { public: InitVal(); InitVal(int val_1, int val_2); InitVal(int val) :val1(val), val2(val){} ~InitVal() {} private: //普通成员就地初始化 int val0 = 0; //普通成员变量 int val1, val2; //静态成员变量 static long val3; //静态常量成员 static const long val4=0; //使用花括号就地初始化 string b{ "hello" }; }; long InitVal::val3 = 0; //构造函数体内初始化 InitVal::InitVal() { val1 = 0; val2 = 0; } //构造函数初始化列表 InitVal::InitVal(int val_1, int val_2):val1(val_1), val2(val_2) { }
- 友元 friend 扩展的友元
//声明一个类为另外一个类的友元时,不再需要使用class关键字
//声明友元类时,甚至可以使用类的别名。class Car; typedef Car BC; class BYD { friend class Car; //C98标准、C++11标准 }; class ChangAn { friend Car; //C++11标准 }; class JILi { //使用别名 friend BC;//C++11标准 }; //为类模板声明友元 //C++11标准 template
class BenChiCar { friend T; }; BenChiCar bc; //int的友元声明会被忽略 BenChiCar bc;
- 函数模板
建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表。这个通用函数就称为函数模板
函数模板定义
声明方式
template应用于函数头
template应用于类头
调用方式
Func(a,b); 自动类型推导,类型要相同
Func(a,b)显示类型调用
template
T mySwap(T &a, T&b)
{
cout << __FUNCTION__ << "typename" << endl;
T t;
t = a;
a = b;
b = t;
cout << "a=" << a << ",b=" << b << endl;
retunr t;
}
template
void mySwap(T &a, T&b)
{
cout << __FUNCTION__ <<"typename" << endl;
T t;
t = a;
a = b;
b = t;
cout << "a=" << a << ",b=" << b << endl;
}
int a = 1, b = 2;
mySwap<>(a, b);//显示类型调用
mySwap(a, b);//显示类型调用
cout << "a=" << a << ",b=" << b << endl;
函数模板与普通函数区别
函数模板不允许自动类型转化;普通函数能够进行自动类型转换
函数模板可以像普通函数一样被重载;C++编译器优先考虑普通函数;如果函数模板可以产生一个更好的匹配,那么选择模板; 可以通过空模板实参列表的语法限定编译器只通过模板匹配;
当普通函数和函数模板重载时,如果隐式调用,编译器会优先普通函数
//普通函数 void mySwap(int &a, int &b) { cout << __FUNCTION__ << endl; int t; t = a; a = b; b = t; cout << "a="< void mySwap(T &a, T&b) { cout << __FUNCTION__ <<"typename" << endl; T t; t = a; a = b; b = t; cout << "a=" << a << ",b=" << b << endl; } int a = 1, b = 2; //当普通函数和函数模板重载时,如果隐式调用,编译器会优先普通函数 mySwap(a, b); 此处调用普通函数 //需要使用显示调用 mySwap<>(a, b);//显示类型调用 mySwap
(a, b);//显示类型调用