std::initializer_list的设计很简单,但在classical C++中充当了越来越重要的角色,是标准的一定公民,在编译器级别收到支持。
严格说,native C++不支持不定长参数(在C++/CLI中有个例外),native C++一般通过重载来模拟不定长参数。#include
但通过std::initializer_list让cpp间接支持了不定长参数,但类型要同构的。
很多class都支持std::initializer_list参数的构造,但不支持不定长参数的构造,比如std::vector和std::list。
std::vector vec = {1,2,3,4,5};
std::list lst = {1,2,3,4,5};
但不能这么写:
std::vector vector(1,2,3,4,5); //error
但可以让不定长参数转化为std::initializer_list,比如,我有个自定义的stack类,有如下的构造,调用了placement new:
stack(std::initializer_list const& list)
{
if (list.size() > 0)
pushArray(&*std::begin(list), list.size());
}
定义一个不定长参数的构造,可以轻易地进行转化:
template
stack(Args... args)
{
::new(this)stack({ std::forward(args)... });
}
将std::forward
::new(this)stack({args... });//调用通过初始化列表的构造函数
你想到了委托构造了吗?可以直接委托成其它的构造函数来实现(C++11 new feature)
template
stack(Args... args) : stack({ std::forward(args)... })
{ }
所以,你有了这个构造,就不用多输入一个花括号了:
stack s(1,2,3,4,5); // is ok
标准的不定长数组的展开是通过特化与递归,在此,类型可以是各异的,如下:
template
void print(const T& val)
{
std::cout << val << std::endl;
}
template
void print(const T& val,Args... args)
{
print(val);
print(std::forward(args)...);
}
如果可以就地展开,则不需要递归了,下面使用了逗号运算符号,就能就地展开:
template
void printValue(const T& val)
{
std::cout << val << std::endl;
}
template
void print(Args... args)
{
auto arr = {(printValue(args),0)...};
//st::std::initializer_list{(print(args),0)...}; // is ok
}
逗号运算符是个稍冷僻的概念,如(a,b,c,d,e)的计算结果是最后一个的值:e,但a、b、c、d、e会依次执行。
native c++通过模版使用函数重载模拟了接受多参的函数,而C++/CLI就纯粹多了,不用模版,直接可以声明多参函数,如:
void sum(... cli::array^ args)
{
int ret = 0;
for each(int c in args)
{
ret += c;
}
return ret;
}
...
int val = sum(1,2,3,4,5);
原创不易,拒绝转载。