在阅读其他主题时,我遇到了一种奇怪的行为,至少对我来说是这样。
这个想法源于 auto
和大括号之间的特殊交互。如果你写下以下代码:
auto A = { 1, 2, 3 }
编译器会将A
推导为std::initializer_list
。奇怪的是,类似的规则不仅适用于auto
,其中可能会有特殊原因,而且也适用于其他情况。
如果你写下以下内容:
template<typename T>
void f(std::vector<T> Vector)
{
// do something
}
当然你不能这样调用:
f({ 1, 2, 3});
尽管可以使用花括号初始化
std::vector
,但如果您将std::vector
替换为std::initializer_list
,则调用将起作用,并且编译器将正确推断T
类型为int
。更有趣的是,在前一种情况下,您需要包括#include <vector>
,而在后一种情况下,您不需要#include <initializer_list>
。这让我思考,经过测试后,我发现某种程度上std::initializer_list
不需要自己的头文件,因此它在某种程度上是“基本”功能的一部分。此外,为了使一切都有意义,
std::initializer_list
应该以更或多或少相同的方式将标准对象与可调用对象(在最严格的意义上,即具有operator()
的对象)联系起来。换句话说,未命名的花括号定义应默认为std::initializer_list
,就像lambda(大多数情况下)是未命名的可调用对象一样。这种推理正确吗?此外,这种行为是否可以更改,如果可以,如何更改?
更新:发现从
iostream
中中转地包含了initializer_list
的头文件(非常奇怪)。但是,问题仍然存在:为什么对于std::initializer_list
调用有效,而对于std::vector
不起作用?
<initializer_list>
头文件是不完整的。例如,GCC会报错:无法推断初始化列表的类型,因为未找到std::initializer_list
;请包含<initializer_list>
。 - EvgT
推断为initializer_list
,而vector
不能容纳它。如果你只是写成了void f(std::vector<int> v)
,那么调用f({1,2,3});
就可以正常工作了。我记得Scott Myers曾经谈到过initializer_list
以及它与auto
和vector
之间的奇怪交互,但我需要看看是否能找到相关内容。 - Tas