Why isn't std::initializer_list a language built-in?

emesx picture emesx · Mar 4, 2013 · Viewed 9.2k times · Source

Why isn't std::initializer_list a core-language built-in?

It seems to me that it's quite an important feature of C++11 and yet it doesn't have its own reserved keyword (or something alike).

Instead, initializer_list it's just a template class from the standard library that has a special, implicit mapping from the new braced-init-list {...} syntax that's handled by the compiler.

At first thought, this solution is quite hacky.

Is this the way new additions to the C++ language will be now implemented: by implicit roles of some template classes and not by the core language?


Please consider these examples:

   widget<int> w = {1,2,3}; //this is how we want to use a class

why was a new class chosen:

   widget( std::initializer_list<T> init )

instead of using something similar to any of these ideas:

   widget( T[] init, int length )  // (1)
   widget( T... init )             // (2)
   widget( std::vector<T> init )   // (3)
  1. a classic array, you could probably add const here and there
  2. three dots already exist in the language (var-args, now variadic templates), why not re-use the syntax (and make it feel built-in)
  3. just an existing container, could add const and &

All of them are already a part of the language. I only wrote my 3 first ideas, I am sure that there are many other approaches.

Answer

Steve Jessop picture Steve Jessop · Mar 4, 2013

There were already examples of "core" language features that returned types defined in the std namespace. typeid returns std::type_info and (stretching a point perhaps) sizeof returns std::size_t.

In the former case, you already need to include a standard header in order to use this so-called "core language" feature.

Now, for initializer lists it happens that no keyword is needed to generate the object, the syntax is context-sensitive curly braces. Aside from that it's the same as type_info. Personally I don't think the absence of a keyword makes it "more hacky". Slightly more surprising, perhaps, but remember that the objective was to allow the same braced-initializer syntax that was already allowed for aggregates.

So yes, you can probably expect more of this design principle in future:

  • if more occasions arise where it is possible to introduce new features without new keywords then the committee will take them.
  • if new features require complex types, then those types will be placed in std rather than as builtins.

Hence:

  • if a new feature requires a complex type and can be introduced without new keywords then you'll get what you have here, which is "core language" syntax with no new keywords and that uses library types from std.

What it comes down to, I think, is that there is no absolute division in C++ between the "core language" and the standard libraries. They're different chapters in the standard but each references the other, and it has always been so.

There is another approach in C++11, which is that lambdas introduce objects that have anonymous types generated by the compiler. Because they have no names they aren't in a namespace at all, certainly not in std. That's not a suitable approach for initializer lists, though, because you use the type name when you write the constructor that accepts one.