特殊用途语言特性

默认实参

默认形参声明

在给定的作用域中,一个形参只能被赋予一次默认实参,这意味着在函数的多个声明中,只能为之前那些没有默认值的形参添加默认参数,而且该形参右侧的所有形参必须都有默认值。

默认形参初始值

局部变量不可以作默认实参,除此之外只要表达式的类型能转换成形参需要的类型,该表达式就可以作默认实参。

int w = 80;
char def = ' ';

void test(int a = w, char c= def)
{
	cout << a << endl;
	cout << c << endl;
}

int main()
{
	int w = 100;  //隐藏了外层定义的w,但是没有改变默认值
	def = '*';  //会改变默认实参的值
	test();

   return 0;
}

内联函数和 constexpr 函数

调用函数比一般求等价表达式的值要慢一些,一次函数调用包含着一系列的工作:调用前要保存寄存器,并在返回时恢复;可能需要拷贝实参;程序转向新的位置执行。

内联函数可以避免函数调用的开销,通常就是将它在每个调用点上“内联的”展开。

inline const string &shorterString(const string &str1, const string &str2)
{
	return str1.size() <= str2.size() ? str1 : str2;
}

调用时:

cout<<shorterString(s1,s2)<<endl;

在编译的过程中展开成类似下面的形式:

cout<<str1.size() <= str2.size() ? str1 : str2<<endl;

注意:

  • 内联声明只是想编译器发出一个请求,编译器可以选择忽略这个请求。
  • 内联机制一般用于优化规模较小、流程直接、频繁调用的函数。
  • 很多编译器不支持内联递归函数。

constexpr

constexpr 函数是指用于常量表达式的函数。

定义 constexpr 函数:

  • 函数的返回类型以及所有的形参类型都得是字面值类型。
  • 函数体内有且只有一条return 语句。
constexpr int new_sz(){	return 42;}

int main()
{
   constexpr int foo = new_sz();
   return 0;
}

new_sz 没有参数,编译器在程序编译时会验证 new_sz 函数返回的是不是常量表达式,所以可以使用 new_sz 函数初始化 constexpr 类型的变量。

执行该初始化任务时,编译器把对 constexpr 函数的调用结果替换成其结果值,为了能够在编译过程中随时展开, constexpr 函数被隐式地指定为内联函数。

注意:

  • constexpr 函数返回的不一定是常量表达式:
constexpr size_t scale(size_t cnt) {return new_sz() * cnt};

如果scale 的实参是常量表达式,那么它的返回值也是常量表达式,反之则不然:

int arr[scale(2)]; //正确,scale(2)是常量表达式
int i = 2;	// i 不是常量
int a2[sclae(i)]; //错误,scale(i)不是常量表达式
  • constexpr 函数体内也可以包含其他语句,只要这些语句不执行任何操作就行,例如:空语句,类型别名,using 声明。

调试帮助

assert 预处理宏

assert 是一种预处理宏,所谓的预处理宏其实就是一个预处理变量,它的行为类型于内联函数,assert 宏使用一个表达式作为条件:

assert(expr);
  • 首先会对 expr 求值,如果表达式为假,assert 输出信息并终止程序的执行,如果表达式为真,assert 什么也不做。
  • assert 宏定义在 cassert 头文件中,预处理器的名字由预处理器而非编译器管理。
  • 和预处理变量一样,宏名字在程序中必须唯一,含有 cassert 头文件的程序不能再定义名为 assert 的变量、函数或者其它实体。
  • assert 宏通常是用来检查不能发生的条件。
  • assert 宏可以作为一种调试程序的辅助手段,但是不能用它替代真正的运行时逻辑检查,也不能替代程序本身应该包含的错误检查。

NDEBUG预处理变量

assert 的行为依赖于一个名为 NDEBUG 的预处理变量的状态,如果定义了 NDEBUG ,则 assert 什么也不做。默认情况是没有定义 NDEBUG

C++ 预处理中定义的对于程序调试很有用的名字:

  • __func__ :存放当前调试函数的名字。
  • __FILE__ :存放当前文件名的字符串字面值。
  • __LINE__ :存放当前行号的整型字面值。
  • __TIME__ :存放文件编译时间的字符串字面值。
  • __DATE__ :存放文件编译日期的字符串字面值。
原文地址:https://www.cnblogs.com/xiaojianliu/p/12498116.html