Reinterpret_cast для диапазона обертокC++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Reinterpret_cast для диапазона оберток

Сообщение Anonymous »

Учитывая следующую обертку (упрощенно):

Код: Выделить всё

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);
(Примечание: Мой текущий вариант использования — повторяющееся поле protobuf, но это может быть любой контейнер, над которым я не могу контролировать).
Насколько я понимаю, поскольку стандартный макет 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());
}
Хммм... похоже, что согласно [expr.new] (21.4), размещение массива new может добавить неуказанные накладные расходы, поэтому оно может не работать для этой цели. Или, может быть, я неправильно понимаю?

Редактировать 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))));
}
Но, похоже, вместо этого мне нужен start_lifetime_as_array, и я не знаю, как его реализовать.

Подробнее здесь: https://stackoverflow.com/questions/791 ... f-wrappers
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»