Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementation of std::initializer_list

Tags:

I have been looking at how the initializer_list is implemented so I found section 18.9 of the standard and found a simple enough looking interface. I thought it would be instructive to make my own version which I named MyNamespace::InitializerList and a use case:

template<class T> class ArrayPrinter { public:     ArrayPrinter(MyNamespace::InitializerList<T> list)     {         for (auto i : list) cout << i << endl;     } };  ...  ArrayPrinter ap{ {1,2,3} }; 

I was surprised to find that this did not work and the compiler complained that it couldn't find a suitable constructor (it wanted to give me 3 arguments but section 18.9 only describes a default constructor).

After a bit of fiddling I found that my class had to be named exactly std::initializer_list in order to work. I could also alias std::initializer_list it into MyNamespace but I could not alias MyNamespace::InitializerList asstd::initializer_list.

It seems that this it is not really a language feature as it depends on the standard library?

The main point to my question is why the name is so important and what were those 3 arguments it was trying to pass to the constructor?

like image 633
DrYap Avatar asked Aug 10 '13 17:08

DrYap


2 Answers

The name is important because the standard says it is. The standard needs some way for you to be able to say, "this constructor can be passed a braced-init-list containing a sequence of values of the type T". That way was given the name "std::initializer_list".

You cannot make a class that has all of the language properties of initializer_list. You can make one that satisfies the conditions of the type specified by section [initializer.list.syn] of the standard. But you'll notice that the only constructor specified there is a default constructor. The only way to create an initializer_list with actual elements relies on the compiler, not user-land code.

So you can't replicate everything about initializer_list. Just as you can't replicate std::type_info. The C++ standard library is not optional.

like image 76
Nicol Bolas Avatar answered Oct 30 '22 12:10

Nicol Bolas


This answer is not entirely accurate. It is possible to create a fully functional std::initializer_list - it just needs to meet the specific requirements of the target compiler.

For GCC and clang that requirement is a private ctor. Here is the libc++ implementation (which also happens to work fine with GCC 8.3):

template<class _Ep> class initializer_list {     const _Ep* __begin_;     size_t    __size_;          inline     constexpr     initializer_list(const _Ep* __b, size_t __s) noexcept         : __begin_(__b),           __size_(__s)     {} public:     typedef _Ep        value_type;     typedef const _Ep& reference;     typedef const _Ep& const_reference;     typedef size_t    size_type;          typedef const _Ep* iterator;     typedef const _Ep* const_iterator;          inline     constexpr     initializer_list() noexcept : __begin_(nullptr), __size_(0) {}          inline     constexpr     size_t    size()  const noexcept {return __size_;}          inline     constexpr     const _Ep* begin() const noexcept {return __begin_;}          inline     constexpr     const _Ep* end()   const noexcept {return __begin_ + __size_;} };  template<class _Ep> inline constexpr const _Ep* begin(initializer_list<_Ep> __il) noexcept {     return __il.begin(); }  template<class _Ep> inline constexpr const _Ep* end(initializer_list<_Ep> __il) noexcept {     return __il.end(); } 
like image 21
JakeSays Avatar answered Oct 30 '22 13:10

JakeSays