Inspired by this question I started wondering if there was a way to create an std::initializer_list from a std::vector.
Given that c++17 guarantees RVO, it seemed to me that it might be possible by building a compile-time dispatch table of initialisation functions.
Here's the first attempt at the code to do it:
#include <initializer_list>
#include <vector>
#include <iostream>
#include <array>
#include <stdexcept>
namespace impl
{
template<class T, std::size_t...Is>
auto as_init_list(std::vector<T> const& v, std::index_sequence<Is...>)
{
auto ret = std::initializer_list<T>
{
v[Is]...
};
return ret;
}
template<class T, std::size_t N>
auto as_init_list(std::vector<T> const& v)
{
auto ret = as_init_list(v, std::make_index_sequence<N>());
return ret;
}
template<class T, std::size_t...Is>
constexpr auto as_init_list_vtable(std::index_sequence<Is...>)
{
using ftype = std::initializer_list<T>(*)(std::vector<T> const&);
auto ret = std::array<ftype, sizeof...(Is)>
{{
&as_init_list<T, Is>...
}};
return ret;
}
template<class T, std::size_t N>
constexpr auto as_init_list_vtable()
{
auto ret = as_init_list_vtable<T>(std::make_index_sequence<N>());
return ret;
}
}
template<class T, std::size_t Limit = 100>
auto as_init_list(std::vector<T> const& vec)
-> std::initializer_list<T>
{
if (vec.size() >= Limit)
throw std::invalid_argument("too long");
static const auto table = impl::as_init_list_vtable<T, Limit>();
auto ret = table[vec.size()](vec);
return ret;
}
int main()
{
std::vector<int> v = { 1, 2, 3, 4 };
auto i = as_init_list(v);
for (auto&& x : i)
{
std::cout << x << '\n';
}
}
Of course, as half-expected, the output appears to be UB:
4200240
32765
0
0
http://coliru.stacked-crooked.com/a/1bf92111619317dd
In this (admittedly unusual and perverse case) I seem to have transgressed some rule around the lifetime of the elements of the items in the initializer_list, but at first glance it seems to me that the code should be valid (because of guaranteed RVO).
Am I right or wrong? Does the standard cover this scenario?