c++ - [[no_unique_address]] 和两个相同类型的成员值

标签 c++ struct c++20 memory-layout object-identity

我正在使用 c++20 中的 [[no_unique_address]]

cppreference 的示例中我们有一个空类型 Empty 和类型 Z

struct Empty {}; // empty class

struct Z {
    char c;
    [[no_unique_address]] Empty e1, e2;
};

显然,Z 的大小必须至少为 2,因为 e1e2 的类型是相同。

但是,我真的想要 Z 大小为 1。这让我开始思考,如何将 Empty 包装在某个包装类中,并使用额外的模板参数来强制执行不同类型的 e1e2

template <typename T, int i>
struct Wrapper : public T{};

struct Z1 {
    char c;
    [[no_unique_address]] Wrapper<Empty,1> e1;
    [[no_unique_address]] Wrapper<Empty,2> e2;
};

不幸的是,sizeof(Z1)==2。有没有办法让 Z1 的大小为 1?

我正在使用 gcc 版本 9.2.1clang 版本 9.0.0 进行测试

<小时/>

在我的应用程序中,我有很多空的表单类型

template <typename T, typename S>
struct Empty{
    [[no_unique_address]] T t;
    [[no_unique_address]] S s;
};

如果 TS 也是空类型并且不同,那么这是一个空类型!即使 TS 是相同类型,我也希望此类型为空。

最佳答案

Which is an empty type if T and S are also empty types and distinct! I want this type to be empty even if T and S are the same types.

你无法理解这一点。从技术上讲,即使 TS 是不同的空类型,您甚至不能保证它是空的。请记住:no_unique_address 是一个属性;它隐藏对象的能力完全取决于实现。从标准的角度来看,您无法强制规定空对象的大小。

随着 C++20 实现的成熟,您应该假设 [[no_unique_address]] 通常会遵循空基优化规则。也就是说,只要同一类型的两个对象不是子对象,您就可能期望隐藏。但在这一点上,这有点运气。

至于TS是同一类型的具体情况,这是根本不可能的。尽管名称“no_unique_address”具有含义,但实际情况是,C++ 要求,给定两个指向同一类型对象的指针,这些指针要么指向同一对象,要么具有不同的地址。我将其称为“唯一身份规则”,并且 no_unique_address 不会影响这一点。来自 [intro.object]/9 :

Two objects with overlapping lifetimes that are not bit-fields may have the same address if one is nested within the other, or if at least one is a subobject of zero size and they are of different types; otherwise, they have distinct addresses and occupy disjoint bytes of storage.

声明为 [[no_unique_address]] 的空类型的成员大小为零,但具有相同的类型使得这是不可能的。

确实,仔细想想,尝试通过嵌套隐藏空类型仍然违反了唯一标识规则。考虑您的 WrapperZ1 案例。给定一个作为 Z1 实例的 z1,很明显 z1.e1z1.e2 是不同的对象具有不同的类型。但是,z1.e1 不嵌套在 z1.e2 中,反之亦然。虽然它们具有不同的类型,但 (Empty&)z1.e1(Empty&)z1.e2 并不是不同的类型。但它们确实指向不同的对象。

根据唯一身份规则,它们必须具有不同的地址。因此,即使 e1e2 名义上是不同的类型,它们的内部也必须遵守同一包含对象中其他子对象的唯一标识。递归地。

无论您如何尝试,在目前的 C++ 中,您想要的都是不可能的。

关于c++ - [[no_unique_address]] 和两个相同类型的成员值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59109110/

相关文章:

c++ - C++中的结构构造函数?

c++ - C++20 的内存模型与 C++11 的内存模型有何不同?

c++ - 将其返回值保存在 lambda 函数中时,std::ranges::sort 不能用作 'constexpr' 函数

C++20 <chrono> 嵌套名称说明符中使用的不完整类型

c++ - 匹配号码

delphi - Delphi 中 CONTAINING_RECORD C 宏的等效函数是什么?

c - 当结构定义具有指针时分配结构

c++ - 打破C++中的封装

c++ - C++11 中类型的逐字节拷贝?

C++11 线程不加入