Код: Выделить всё
template class Wrapper {
public: auto val() { return t; }
private: T t;
};
Код: Выделить всё
template
auto suspect(auto& ar) {
return std::span(reinterpret_cast(ar.data()), ar.size());
}
Код: Выделить всё
auto ar = external_func_returning_container();
auto sp = suspect(ar);
external_func_accepting_span_of_wrappers(sp);
Насколько я понимаю, поскольку стандартный макет Wrapper позволяет привести указатель на него к указателю на его обернутый элемент.
Однако я сильно подозреваю, что шаблон подозреваемого() в том виде, в котором он написан, вызывает неопределенное поведение, главным образом потому, что фактических объектов Wrapper нет.
Мои вопросы:
- Прав ли я, полагая, что подозреваемый() вызывает UB?
- Если да, то есть ли способ переписать его, не вызывая UB или не копируя потенциально большой контейнер (с использованием функций C++20 или C++23)?
- Если невозможно сделать это переносимым способом, есть ли какой-нибудь способ, специфичный для Clang?
Будет ли новое место размещения работать?
Код: Выделить всё
template
auto suspect(auto& ar) {
return std::span(new(ar.data()) Wrapper[ar.size()], ar.size());
}
Редактировать 2: (в ответ на комментарии и ответы)
В настоящее время я использую Clang17, который не поддерживает std::start_lifetime_as.
На самом деле, согласно cppreference, ни один компилятор в настоящее время не поддерживает его.Однако ответ SO предполагает, что его можно реализовать следующим образом:
Код: Выделить всё
template
requires (std::is_trivially_copyable_v && std::is_implicit_lifetime_v)
T* start_lifetime_as(void* p) noexcept
{
return std::launder(static_cast(std::memmove(p, p, sizeof(T))));
}
Подробнее здесь: https://stackoverflow.com/questions/791 ... f-wrappers
Мобильная версия