initializer_list
对于未知数量的参数,的实际好处和目的是什么?为什么不直接使用vector
并完成它呢?
事实上,它听起来只是一个vector
有另一个名字的。何苦?
我看到的唯一“好处”initializer_list
是它具有const
元素,但这似乎不足以成为发明这种全新类型的理由。const vector
(毕竟你可以只使用 a 。)
那么,我错过了什么?
initializer_list
对于未知数量的参数,的实际好处和目的是什么?为什么不直接使用vector
并完成它呢?
事实上,它听起来只是一个vector
有另一个名字的。何苦?
我看到的唯一“好处”initializer_list
是它具有const
元素,但这似乎不足以成为发明这种全新类型的理由。const vector
(毕竟你可以只使用 a 。)
那么,我错过了什么?
它是程序员和编译器之间的一种契约。程序员说{1,2,3,4}
,编译器从中创建一个类型的对象initializer_list<int>
,其中包含相同的元素序列。该契约是语言规范对编译器实现的要求。
这意味着,不是程序员手动创建这样的对象,而是编译器创建对象,并将该对象传递给initializer_list<int>
作为参数的函数。
std::vector
实现利用了这个契约,因此它定义了一个构造函数作为initializer_list<T>
参数,以便它可以使用初始化列表中的元素初始化自己。
现在假设一段时间std::vector
没有任何构造函数std::initializer_list<T>
作为参数,那么你会得到这个:
void f(std::initializer_list<int> const &items);
void g(std::vector<int> const &items);
f({1,2,3,4}); //okay
g({1,2,3,4}); //error (as per the assumption)
根据假设,因为std::vector
没有作为参数的构造std::initializer_list<T>
函数,这意味着您不能将{1,2,3,4}
作为参数传递给g()
如上所示,因为编译器无法直接创建out std::vector
of the expression的实例。这是因为程序员和编译器之间从来没有签订过这样的合同,并且是由语言强加的。正是通过,才能创造出自己的表达。{1,2,3,4}
std::initializer_list
std::vector
{1,2,3,4}
现在您将了解,std::initializer_list
可以在需要 . 形式的表达式的任何地方使用{value1, value2, ...., valueN}
。这就是为什么标准库中的其他容器也定义了std::initializer_list
作为参数的构造函数。通过这种方式,没有容器依赖于任何其他容器来构造 形式的表达式{value1, value2, ...., valueN}
。
希望有帮助。
好吧,std::vector
必须使用initializer_list
来获取该语法,因为它显然不能使用自己。
无论如何,initializer_list
旨在极其轻量级。它可以使用最佳存储位置并防止不必要的复制。使用vector
,您总是会获得堆分配,并且很有可能获得比您想要的更多的副本/移动。
此外,语法有明显的差异。其中之一是模板类型推导:
struct foo {
template<typename T>
foo(std::initializer_list<T>) {}
};
foo x{1,2,3}; // works
vector
不会在这里工作。
initializer_list
over的最大优点vector
是它允许您就地指定特定的元素序列,而无需专门的处理来创建该列表。
即使您确切知道哪些元素将被推入向量中,这也使您免于设置多个调用push_back
(或for
循环)来初始化 a 。vector
事实上,vector
它本身有一个构造函数接受一个initializer_list
更方便的初始化。我想说这两个容器是互补的。
// v is constructed by passing an initializer_list in input
std::vector<std::string> v = {"hello", "cruel", "world"};
当然,重要的是要意识到它initializer_list
确实有一些限制(不允许缩小转换),这可能使其在某些情况下不合适或无法使用。