直接初始化和拷贝初始化

如果使用=来初始化一个变量,实际上执行的是拷贝初始化。编译器把等号右边的初始值拷贝到新创建的对象中去。 如果不使用等号,则执行的是直接初始化

含有可变形参的函数

C++11提供了两种主要的方法:

  • initializer_list方法,要求实参类型必须相同1
  • 可变参数模板

另外传统C++还给与了一个与C语法兼容的方法

  • 省略符形参

initializer_list的用法

void error_msg(ErrCode e, initializer_list<string> il) {
  cout << e.msg() << ": ";
  for (const auto &elem : il) {
    cout << elem << " ";
  cout << endl;
}
error_msg(ErrCode(32), {"functionX", " is not ", "right"});

省略符形参

省略符形参是为了方便C++程序访问某些特殊的C代码而设置的。这些代码使用了名为varargs的C标准库的功能。通常,省略符形参不应该用于其他目的。
省略符形参应该仅仅用于C/C++通用的类型。特别需要注意的是,大多数类类型的对象传递给省略符形参时,都无法正确拷贝。
省略符形参必定在函数定义的最后面。
我们采用 va_start,va_end和va_arg来使用省略符形参
用法如下所示

int sumi(int c...) {
  va_list argptr;
  va_start(argptr, c);
  int sum = c;
  c = va_arg(argptr, int);
  while( 0 != c) {
    sum += c;
    c = va_arg(argptr, int);
  }
  va_end(argptr);
  return sum;

下面分析一下这个过程中的原理
其实va_list只是一个指针。可以认为uint8_t *指针。

当然我们也可以认为是void指针,不过void指针的加减运算是未定义的,即便在大多数编译器中void*指针加减就是以一个字节为单位的.

va_start(argptr, c) 这句宏语句,使得我们把argptr的指针指向,c的下一个位置。
这句话等价于 argptr = (uint8_t *)&c + sizeof(c);

c = va_arg(argptr, int); 这句宏语句,作用是返回参数值,并且将argptr指针指向下一个地址。
这句话等价于 c = * (int *)( (argptr += sizeof(int)) -sizeof(int) )
这句话比较复杂,我们可以拆解为

 argptr += sizeof(int);
 c = * (int *) (argptr - sizeof(int));

va_end(argptr) 将argptr置为空指针。 当然这句话其实没有必要,只要保证以后不会使用argptr变量就行了。
在VC中,这几个宏的定义是

#define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1)) //类型n的大小  
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) //ap指向第一个不定参数地址  
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) //下一个参数地址  返回当前ap指向的值,并且让ap指向下一个参数的地址
#define va_end(ap) ( ap = (va_list)0 ) // 将指针置为无效  

这里还有些题外话,C语言的这种方式,使得我们的函数的参数长度不定。在汇编上,体现为函数调用时,加入参数栈的过程,参数栈的长度,函数本身不知道。只有调用这个函数的函数才知道。 此时,函数参数栈的压栈和出栈都由调用这个函数的函数来做。这种调用方法被称为 __cdecl. 另外还有一种方式,__stdcall,是由函数自身来清理。这要求函数自身知道自己的参数栈需要多少空间。

可变长模板

可变长模板,将会在模板一章细述

constexpr函数

constexpr是指能用于常量表达式的函数。定义constexpr函数必须遵守以下规定

  • 函数的返回值类型,以及所有形参的类型必须都是字面值
  • 函数体中有且只有一条return语句2

constexpr被隐式的指定为内联函数。


  1. initializer_list还可用于类的构造函数,使得我们能使用大括号进行初始化类。 

  2. 在C++14中,constexpr可以使用多种逻辑控制结构了。包括if 和switch等条件语句,支持循环,其中包括基于区间(range)的for 循环。