std :: initializer_list,带括号的初始化和标头

时间:2018-10-22 08:01:39

标签: c++ templates initializer-list

在阅读另一个主题时,我遇到了一种奇怪的行为,至少对我而言。 这整个思想源于auto和花括号之间的特殊交互。如果您编写类似这样的内容:

auto A = { 1, 2, 3 }

编译器将推论Astd::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

3 个答案:

答案 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