std::initializer_list, braced initialization and header

Deadly 提交于 2019-12-08 14:56:41

问题


While reading about a different topic I came across a weird behaviour, at least to me. This whole thought originated from the special interactions between auto and braces. If you write something like:

auto A = { 1, 2, 3 }

the compiler will deduce A to be a std::initializer_list. The weird thing is that a similar rule applies not only to auto, where there can be special reasons for it, but also to other things. If you write the following:

template<typename T>
void f(std::vector<T> Vector)
{
    // do something
}

you can't of course call it in this way:

f({ 1, 2, 3});

even though a std::vector can be braced initialized. However, if you substitute the std::vector with std::initializer_list, the call works and the compiler will properly deduce int as the type T. The more interesting thing is, however, that in the former case you need to #include <vector>, in the latter you don't need to #include <initializer_list>. This made me think and after a test I realized somehow std::initializer_list don't need its own header, so it is in some way part of the "base" features.

Moreover, for everything to make sense, std::initializer_list should be to standard objects in more or less the same way lambdas are to callable objects (in the strictest meaning, that is an object with a operator()). In other words, unnamed braced definitions should default to std::initializer_list just like lambdas are (mostly) unnamed callable objects.

Is this reasoning correct? Moreover, can this behaviour be changed and, if so, how?

UPDATE: the header for initializer_list was found to be included transitively from iostream (really weird). However, the question remains: why the call works for std::initializer_list and not for std::vector?


回答1:


It is ill-formed (so it requires a diagnostic) to not include the initializer_list header if we use std::initializer_list. We can see this from [dcl.init.list]p2:

... The template std::initializer_list is not predefined; if the header <initializer_list> is not included prior to a use of std::initializer_list — even an implicit use in which the type is not named (9.1.7.4) — the program is ill-formed.

Mostly likely you are including the header transitively, which is well-formed but makes your code more fragile, so include what you use.

We can see from a live godbolt example that having no includes we obtain a diagnostic as required from gcc/clang/MSVC e.g.:

error: use of undeclared identifier 'std'    
void foo( std::initializer_list<int>) {
          ^

and including either <vector> or <iostream> we no longer obtain a diagnostic.

Why it does not deduce as you expect is covered by [temp.deduct.type]p5 which tells us this is a non-deduced context:

The non-deduced contexts are:
...
- A function parameter for which the associated argument is an initializer list ([dcl.init.list]) but the parameter does not have a type for which deduction from an initializer list is specified ([temp.deduct.call]).> [ Example:

template<class T> void g(T);
g({1,2,3});                 // error: no argument deduced for T

— end example  ]
...

also see [temp.deduct.call]p1:

... Otherwise, an initializer list argument causes the parameter to be considered a non-deduced context ([temp.deduct.type]) ...




回答2:


You're probably including the header transitively from <vector> or <iostream>, keep in mind that the standard explicitly enforces a non-deduced context for the std::vector case

[temp.deduct.type]/p5

The non-deduced contexts are:

...

  • A function parameter for which the associated argument is an initializer list ([dcl.init.list]) but the parameter does not have a type for which deduction from an initializer list is specified ([temp.deduct.call]).

Cfr. cppreference ex.6




回答3:


The CPP online reference for <vector> shows that <initializer_list> is included in its header.

GCC's implementation of <vector> includes <initializer_list>. This is probably true of other implementations as well. This is the reason you did not have to include <initializer_list> separately.

Check out this source for GCC 4.6.2 which includes <initializer_list> in the <vector> header. https://gcc.gnu.org/onlinedocs/gcc-4.6.2/libstdc++/api/a01069_source.html



来源:https://stackoverflow.com/questions/52924740/stdinitializer-list-braced-initialization-and-header

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!