Convert a vector<T> to initializer_list<T>

Fil picture Fil · Sep 19, 2013 · Viewed 32.2k times · Source

Everyone creates std::vector from std::initializer_list, but what about the other way around?

eg. if you use a std::initializer_list as a parameter:

void someThing(std::initializer_list<int> items)
{
...
}

There are times when you have your items in a vector<T> instead of a literal list:

std::vector<int> v;
// populate v with values
someThing(v); // boom! No viable conversion etc.

The more general question is: how to create an stl::initializer_list from a STL iterable, not just std::vector.

Answer

TemplateRex picture TemplateRex · Sep 19, 2013

The answer is NO, you cannot do that.

An object of type std::initializer_list<T> is a lightweight proxy object that provides access to an array of objects of type T. A std::initializer_list object is automatically constructed when:

  • a braced-init-list is used in list-initialization, including function-call list initialization and assignment expressions (not to be confused with constructor initializer lists)
  • a braced-init-list is bound to auto, including in a ranged for loop

As far as library support goes, std::initializer_list only has a default constructor that constructs an empty list, and its iterators are constant. The lack of a push_back() member means you cannot apply e.g. a std::copy with a std::back_inserter iterator adaptor to fill it, and neither can you assign through such iterators directly:

#include <algorithm>
#include <initializer_list>
#include <iterator>
#include <vector>

int main() 
{
    auto v = std::vector<int> { 1, 2 };
    std::initializer_list<int> i;
    auto it = std::begin(i);
    *it = begin(v); // error: read-only variable is not assignable
}

Live Example

If you look at the Standard Containers, in addition to accepting std::initializer_list in their constructors / inserters, they all have constructors / inserters taking an iterator pair, and the implementation is likely to delegate the initializer_list function to the corresponding iterator pair function. E.g. the std::vector<T>::insert function in libc++ is this simple one-liner:

 iterator insert(const_iterator __position, initializer_list<value_type> __il)
        {return insert(__position, __il.begin(), __il.end());}

You should modify your code along similar lines:

void someThing(std::initializer_list<int> items)
{
    someThing(items.begin(), items.end()); // delegate
}

template<class It>
void someThing(It first, It last)
{
    for (auto it = first, it != last; ++it) // do your thing
}

In times when you have your items in a vector instead of a literal list:

std::vector<int> v = { 1, 2 };
auto i = { 1, 2 };
someThing(begin(v), end(v)); // OK
someThing(i); // also OK
someThing({1, 2}); // even better