预定义宏对于多目标平台代码的编写具有重大意义。通过使用#ifdef/#endif
等预处理指令,可以实现一套代码完成多平台支持。
返回所在函数的名字。
可以使用在宏中的#pragma
#define CONCAT(x) PRAGMA(concat on #x)
#define PRAGMA(x) _Pragma(#x)
CONCAT(..\concat.dir)
out:_Pragma(concat on "..\concat.dir")
__VA__ARGS__
变长参数的宏定义指在宏定义中参数列表的最后一个参数为省略号。
预定义宏__VA_ARGS__
可以在宏定义的实现部分替换省略号所代表的字符串
#define PR(...) printf(__VA_ARGS__)
#define LOG(...) { \
fprintf(stderr,"%s: Line %d:\t", __FILE__, __LINE__);\
fprintf(stderr,__VA_ARGS__);\
fprintf(stderr,"\n");\
}
C与C++混用头文件的典型做法。
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
判断编译器是否支持C++11
#if __cplusplus < 201103L
#error "should use C++11 implumentation"
#endif
包括使用assert以及#if和#error配合两种方式。
#ifdef _COMPLEX_H
#error "Never use directly;include instead."
#endif
编译时执行的断言。
典型的实现:Boost内置的BOOST_STATIC_ASSERT断言机制(利用sizeof操作符)。利用“除0”会导致编译器报错这个特性来实现静态断言。
#define assert_static(e) \
do{ \
enum { assert_static__ = 1/(e) }; \
} while (0)
为了解决诊断信息不充分的问题,引入了static_assert断言。
int a = 0;
std::string b = "1";
static_assert(sizeof(a) == sizeof(b), "the type of a and should same");
noexcept表示其修饰的函数不会抛出异常。如果抛出了异常,则会调用std::terminate()终止程序运行。
void except_func() noexcept;
//常量表达式的结果会被转换成一个bool类型的值。如果为真则不会抛出异常,反之则可能抛出。
void except_func() noexcept (常量表达式);
通常可用于模板。
template
void fun() noexcept(noexcept(T())) {}
第二个noexcept操作符的参数为一个可能抛出异常的表达式的时候,其返回值时false,反之为true。
标准允许使用等号=或者花括号{}进行就地的非静态成员变量初始化。
struct init{ int a = 1; double b {1.2}; }
在类的声明中对非静态成员进行就地列表初始化可以降低程序员的工作量。(创建多个构造函数时)
class Test{
public:
Test(){};
Test(int a):m_number(a){};
Test(string str):m_str(str){};
Test(int a,string str):m_number(a),m_str(str){};
private:
int m_number = 1;
string m_str = "init";
};
对非静态成员变量使用sizeof操作合法。不需要实例化。
声明一个类为另一个类的友元时,不再需要class关键字,同时支持别名的方式。
通过类模板声明友元。
class P;
template class People {
friend T;
};
People PP;
People Pi;
用来阻止继续重写。使派生类不可覆盖它所修饰的虚函数。
struct Object{
virtual void fun() = 0;
};
struct Base : public Object{
void fun() final;
};
struct Derived: public Base{
void fun(); //无法通过编译
};
如果派生类在虚函数声明时使用了override描述符,那么该函数必须重载其基类中的同名函数,否则无法通过编译。
无法从函数实参中推导出类型时,默认模板参数会被使用。
template
void f(T t = 0, U u = 0);
void g(){
f(1,'c');// 1,'c'
f(1); // 1,0
f(); // 错误 T无法被推导
f();//0,0
f();//0,0
}
使用了相同模板函数且参数类型一致时,编译器会在目标文件中生成两份一摸一样的函数代码。而为了节约空间,链接器在链接的时候会通过编译器辅助的手段将重复的模板函数删掉,只保留单个副本。
多处的模板实例化都需要编译器去做实例化的工作,而在链接的时候,还需要移出重复的实例化代码。导致编译器产生大量的冗余代码,增加编译时间和链接时间。使用“外部的”模板可以解决这个问题。
template void fun(T) {}
#include "test.h"
template void fun(int); //显示的实例化
void test1() { fun(3); }
#include "test.h"
extern template void fun(int); //外部模板的声明
void test1() { fun(3); }
外部模板不能用于一个静态函数(即文件域函数),但可以用于类静态函数(静态函数没有外部链接属性)。