Я хотел бы «материализовать» список типов переменных в initializer_list связанных значений.
Например, имея std::tuple
из нескольких std::integral_constant<T, x>
получить std::initializer_list<T>{...}
,
В общем случае я хотел бы получить initializer_list некоторого сложного типа, например std::string
,
Но следующий простой пример дает мне сбой при компиляции Clang (хотя он работает с GCC, по крайней мере, на Coliru), поэтому я подозреваю UB (или ошибку в Clang):
template <class... Ts>
std::initializer_list<const std::string> materialize()
{
return {
std::to_string(Ts::value)...
};
}
void print_out()
{
for (const auto & x : materialize<std::true_type, std::false_type>()) {
std::cout << x << "\n";
}
}
Итак, законен ли такой кодекс? В С ++ 11/14/17?
Две вещи о initializer_list:
Списки инициализаторов могут быть реализованы как пара указателей или указатель
и длина. Копирование списка std :: initializer_list не копирует
базовые объекты.
а также
Базовый массив не гарантированно существует после жизни
исходный объект списка инициализатора закончился. Хранение для
std :: initializer_list не указан (то есть он может быть автоматическим,
временная или статическая постоянная память, в зависимости от ситуации).
так в этой строке
return {
std::to_string(Ts::value)...
};
вы создаете локальный массив, initializer_list сохраняет указатель на начало / конец этого массива, когда функция выходит из области видимости, у вас есть висячие указатели.
Основной массив std::initializer_list
это местный временный объект на самом деле. Когда выйти из materialize
это было уничтожено. Копирование std::initializer_list
не копирует базовый массив, содержимое возвращаемого std::initializer_list
всегда недействителен и пытается получить доступ к содержимому возвращенного std::initializer_list
приводит к UB.
(акцент мой)
Списки инициализаторов могут быть реализованы в виде пары указателей или указателей
и длина. Копирование списка std :: initializer_list не копирует
базовые объекты.Базовый массив является временным массивом типа
const T[N]
, в
который каждый элемент инициализируется копией (за исключением того, что сужение
преобразования недействительны) из соответствующего элемента
оригинальный список инициализаторов. Время жизни базового массива
так же, как любой другой временный объект, за исключением того, что инициализация
Объект initializer_list из массива продлевает время жизни
массив точно так же, как привязка ссылки к временному (с тем же
исключения, например, для инициализации нестатического члена класса).
базовый массив может быть размещен в постоянной памяти.