在什么情况下,标准要求与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
更改大小或对齐方式,这可能会破坏我的整个方法并导致计算错误的偏移量。