Convert a vector<T> to initializer_list<T>
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
Apparently no, it is not possible. There is no such constructor (and I believe for good reasons), std::initializer_list
is a weird creature.
What you could do instead is to change someThing()
to accept a pair of iterators. In that way you get what you want, provided you can change the signature of that function (it isn't in a third party library, etc).
Yes you can do this, but you don't want to do it, because how you have to do it is pretty silly.
First, determine what the max length of your list is. There must be a max length, because size_t
is not unbounded. Ideally find a better (smaller) one, like 10.
Second, write magic switch code that takes a run-time integer, and maps it to a compile time integer, and then invokes a template class or function with that compile time integer. Such code needs a max integer size -- use the max length above.
Now, magic switch the size of the vector into a compile time length.
Create a compile time sequence of integers, from 0
to length-1
. Unpack that sequence in a initializer_list
construction, each time invoking []
on the std::vector
. Call your function with that resulting initializer_list
.
The above is tricky and ridiculous and most compilers will blow up on it. There is one step I'm uncertain of the legality of -- is the construction of an initializer_list
a legal spot to do varardic argument unpacking?
Here is an example of a magic switch: Can I separate creation and usage locations of compile-time strategies?
Here is an example of the indices, or sequence, trick: Constructor arguments from tuple
This post should only be of theoretical interest, because practically this is a really silly way to solve this problem.
Doing it with an arbitrary iterable is harder, without doing n^2 work. But as the above is already ridiculous enough, and the arbitrary iterable version would be more ridiculous... (Maybe with a pack of lambdas -- getting it so that the arguments are evaluated in order could be tricky. Is there a sequence point between the evaluation of the various arguments to an initializer list?)