在阅读另一个主题时,我遇到了一种奇怪的行为,至少对我而言。
这整个思想源于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
,该调用将起作用,并且编译器将正确推断出int
作为类型T
。但是,更有趣的是,在前一种情况下,您需要#include <vector>
,在后一种情况下,您不需要#include <initializer_list>
。这让我开始思考,经过测试,我意识到std::initializer_list
不需要自己的标头,因此在某种程度上是“基本”功能的一部分。
此外,为了使所有事情都有意义,std::initializer_list
应该或多或少地与标准对象一样,即lambdas与可调用对象(严格意义上就是具有operator()
的对象) )。换句话说,未命名的括号定义应默认为std::initializer_list
,就像lambda是(大部分)未命名的可调用对象一样。
这个推理正确吗?而且,这种行为可以改变吗?如果可以,如何改变?
更新:发现initializer_list
的标头是从iostream
传递而来的(确实很奇怪)。但是,问题仍然存在:为什么呼叫适用于std::initializer_list
而不适用于std::vector
?
答案 0 :(得分:9)
如果我们使用initializer_list
,则不包含std::initializer_list
标头的格式不正确(so it requires a diagnostic)。我们可以从[dcl.init.list]p2看到这一点:
...模板std :: initializer_list尚未预定义;如果标题
是 在使用std :: initializer_list之前不包括在内-甚至是隐式使用,其中类型不是 名称(9.1.7.4)-程序格式错误。
您很有可能会传递性地包含标头,该标头格式正确,但会使您的代码更脆弱,因此请包含您使用的标头。
我们从一个生动的示例中可以看到,不包含任何内容,我们可以根据gcc/clang/MSVC的要求获取诊断信息,例如:
error: use of undeclared identifier 'std'
void foo( std::initializer_list<int>) {
^
并包括<vector>
或<iostream>
我们no longer obtain a diagnostic。
[temp.deduct.type]p5涵盖了为什么它不能如您所愿地推论,告诉我们这是一个非推论上下文:
非推论上下文是:
...
-函数参数,其关联参数为初始值设定项列表([dcl.init.list]),但该参数不具有为其指定从初始值设定项列表进行演绎的类型([temp.deduct.call])。 [示例:template<class T> void g(T); g({1,2,3}); // error: no argument deduced for T
-示例example]
...
另请参阅[temp.deduct.call]p1:
...否则,初始化程序列表参数会导致该参数被视为非推导上下文([temp.deduct.type])...
答案 1 :(得分:1)
您可能正在从<vector>
或<iostream>
传递标题,请记住,std::vector
情况下的标准explicitly enforces a non-deduced context
[温度扣除类型] / p5
非推论上下文是:
...
- 一个函数参数,其关联参数为初始值设定项列表([dcl.init.list]),但该参数不具有为其指定从初始值设定项列表中推论的类型([temp.deduct.call]) 。
CFR。 cppreference ex.6
答案 2 :(得分:0)
<vector>
的CPP在线参考显示其标题中包含import
。
GCC的<initializer_list>
实现包括<vector>
。其他实现也可能如此。这就是您不必单独包含<initializer_list>
的原因。
签出GCC 4.6.2的源,该源在<initializer_list>
标头中包含<initializer_list>
。
https://gcc.gnu.org/onlinedocs/gcc-4.6.2/libstdc++/api/a01069_source.html