在什么情况下标准要求T
与std::aligned_storage<sizeof(T), alignof(T)>
具有完全相同的大小和对齐方式?
我认为答案总是如此,但是从other SO answers today开始,我了解到,对于一些不起眼的T
,它可能是实现定义的。如果实现支持扩展对齐类型,例如128位整数,那么如果我理解正确的话std::aligned_storage
是否最终将具有128位对齐,则由实现决定。
还有其他类型T
,问题的答案可能是实现定义的吗?
在我的应用程序中,我基本上有一个未知类型的元组std::tuple<T, U, V>
,我希望能够获得成员T
的{em>偏移,{{1这个元组中的{},U
尽可能高效,理想情况是在编译时。
(我意识到这是一个非常奇怪的事情。我正在尝试修复一些现有代码,其中使用V
将元组覆盖在“布局兼容”类型之上。不相关的对象之间的类型是非法的,违反了严格的别名规则。如果我能得到成员的抵消,那么我可以将非法演员分解出去。)
AFAIK,这在C ++ 14 reinterpret_cast
中无法完成。但它可以非常接近,我的代码看起来像这样:
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
的类型会改变大小或对齐方式,这可能会破坏我的整个方法并导致计算错误的偏移量。