Вдохновленный этим вопросом Мне стало интересно, есть ли способ создать std::initializer_list
из std::vector
.
Учитывая, что c ++ 17 гарантирует RVO, мне показалось, что это могло бы быть возможно путем построения таблицы диспетчеризации во время компиляции функций инициализации.
Вот первая попытка кода сделать это:
#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';
}
}
Конечно, как и ожидалось, результат выглядит как UB:
4200240
32765
0
0
http://coliru.stacked -crooked.com / а / 1bf92111619317dd
В этом (по общему признанию, необычном и извращенном случае) я, кажется, нарушил какое-то правило вокруг времени жизни элементов элементов в initializer_list, но на первый взгляд мне кажется, что код должен быть действительным (из-за гарантированного РВО).
Я прав или нет? Стандарт охватывает этот сценарий?