默认实参
在函数声明时,给形参赋予一个初始值,实际调用时可以使用这个默认值也可以不使用,不过一旦某个形参有了初始值,后面的也要有
string screen(int ht = 24,int wid = 10,char blackboard = '');
默认实参只能从右往左填补,所以要将常用默认实参的出现在后面,不怎么用的出现在前面
window = screen(, , '?');//错误
window =screen('?');//正确但是不是我们本意,发生了隐式类型转换

默认实参初始值
int w = 10;
char def = '';
int ht();
string screen(int = ht(),int = w,char = def);
void f()
{
    def = '*';//给全局变量def赋值,改变了默认值
    int w = 100;//虽然屏蔽了全局变量的w,但是全局变量w的值没有改变,默认值也没有改变
    window  screen();//调用了ht(),10,‘*’
}

内联函数和constexpr函数
内联函数可避免函数调用的开销,方法就是在函数前面加上inline,但是编译器也可能忽略这个要求,一般内联函数的定义需要放在头文件
constexpr函数用于声明常量表达式,如果要定义一个constexpr函数,必须保证形参和返回值的类型都是字面值类型,且函数体中只能有一个return
constexpr int new()
{
    return 42;
}
constexpr int foo = new();//正确,foo为常量表达式
constexpr的返回值可以不是常量,但是必须是字面值
constexpr int scale(int val)
{
    return 2*val;
}
int arr[scale(2)];//正确,2为常量表达式,返回的也是常量表达式,可以用来构建数组
int i = 2;
int arr2[scale(i)];//错误,不是常量表达式,i需要加上const才能成常量表达式

调试帮助
assert预处理宏:
使用一个表达式作为它的条件,assert(表达式)若为假,输出信息并终止程序的执行,若为真,assert什么也不做
NDEBUG变量:
assert行为依赖于NDEBUG的状态,若定义了NDEBUG,则assert将会什么也不做,一般用#define定义这个变量
assert会有运行开销所以应该作为检查辅助手段,检查却是不可能发生的事情。定义变量后可以使用标准句式检查,若没有定义则执行,若定义了就不再执行花括号的内容
#ifndef NDEBUG
    cerr << __func__ <<endl;
#endif
__func__为发当前调试函数名,还有TIME,DATE,FILE等可以使用