Всегда ли `T` имеет тот же размер и выравнивание, что и` std :: align_storage & lt; sizeof (T), alignof (T) & gt; `

При каких обстоятельствах стандарт требует, чтобы T имеет точно такой же размер и выравнивание, как std::aligned_storage<sizeof(T), alignof(T)> ?

Я думал, что ответ был всегда, но от другие SO ответы сегодня, Я узнал, что для некоторых неизвестных T, это может быть определено реализацией. Если реализация поддерживает расширенные типы выравнивания, такие как 128-битные целые числа, то до реализации std::aligned_storage в итоге получится 128-битное выравнивание, если я правильно понял.

Есть ли другие типы T где ответ на вопрос может быть определен реализацией?


В моем приложении у меня в основном есть кортеж std::tuple<T, U, V> неизвестных типов, и я хочу быть в состоянии получить смещения членов T, U, V в этом кортеже максимально эффективно, в идеале во время компиляции.

(Я понимаю, что это очень странная вещь. Я пытаюсь исправить существующий код, в котором кортеж накладывается поверх «совместимого с макетом» типа, используя reinterpret_cast, Такое приведение между несвязанными объектами является незаконным и нарушает строгие правила наложения имен. Если вместо этого я смогу получить смещения участников, то смогу отсеять нелегальный состав.)

AFAIK, это не может быть сделано в C ++ 14 constexpr, Но это может быть довольно близко, мой код выглядит так:

#include <type_traits>
#include <tuple>
#include <utility>
#include <memory>

template <typename T>
struct tuple_of_aligned_storage;

template <typename... Ts>
struct tuple_of_aligned_storage<std::tuple<Ts...>> {
using type = std::tuple<std::aligned_storage_t<sizeof(Ts), alignof(Ts)>...>;
};

template <typename T>
using tuple_of_aligned_storage_t = typename tuple_of_aligned_storage<T>::type;

template <typename S>
struct offset_helper {

// Get offset of idx'th member
template <std::size_t idx>
static std::ptrdiff_t offset() {
constexpr tuple_of_aligned_storage_t<S> layout{};
// TODO: Do modern compilers optimize `layout` object out of the binary?
// If so, this call is probably inlined.
return reinterpret_cast<const char *>(&std::get<idx>(layout)) - reinterpret_cast<const char *>(&layout);
}
};

int main() {
using T = std::tuple<int, float, double>;
return offset_helper<T>::offset<0>(); // offset of 0'th member
}

В экспериментах большинство современных компиляторов оптимизируют это до постоянной величины, даже несмотря на то, что при этом используются переинтерпретации и тому подобное, и offset функция не может быть отмечена constexpr,

Точка использования std::aligned_storage здесь, даже если члены кортежа не являются конструктивными по умолчанию, имеют нетривиальную инициализацию и т. д., заменяя их на std::aligned_storage делает их тривиально конструктивными без изменения макета кортежа.

Но, если для некоторых типов, поменять тип на std::aligned_storage изменяет размер или выравнивание, что может нарушить весь мой подход и привести к неправильным расчетам смещений.

1

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …