c++ - [[no_unique_address]] 和两个相同类型的成员值
问题描述
我在[[no_unique_address]]
玩c++20
。
在cppreference的示例中,我们有一个空类型Empty
和类型Z
struct Empty {}; // empty class
struct Z {
char c;
[[no_unique_address]] Empty e1, e2;
};
显然, 的大小Z
必须至少2
是因为类型e1
和e2
是相同的。
但是,我真的很想拥有Z
size 1
。这让我想到,Empty
用额外的模板参数包装一些包装类怎么样,这些模板参数强制不同类型的e1
and e2
。
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
. 有没有一个技巧可以使 sizeZ1
成为一个?
我正在测试这个gcc version 9.2.1
和clang version 9.0.0
在我的应用程序中,我有很多空类型的表单
template <typename T, typename S>
struct Empty{
[[no_unique_address]] T t;
[[no_unique_address]] S s;
};
ifT
并且S
也是空类型并且不同,这是一个空类型!我希望这种类型为空,即使T
和S
是相同的类型。
解决方案
if
T
并且S
也是空类型并且不同,这是一个空类型!我希望这种类型为空,即使T
和S
是相同的类型。
你不能得到那个。T
从技术上讲,即使和S
是不同的空类型,您甚至不能保证它是空的。记住:no_unique_address
是一个属性;它隐藏对象的能力完全取决于实现。从标准的角度来看,您不能强制规定空对象的大小。
随着 C++20 实现的成熟,您应该假设它[[no_unique_address]]
通常会遵循空基优化的规则。也就是说,只要两个相同类型的对象不是子对象,您就可以期望隐藏。但在这一点上,这是一种运气。
至于具体情况T
和S
是同一类型,那根本不可能。尽管名称“no_unique_address”有含义,但实际情况是 C++ 要求,给定两个指向相同类型对象的指针,这些指针要么指向同一个对象,要么具有不同的地址。我称之为“唯一身份规则”,no_unique_address
并不影响这一点。来自[intro.object]/9:
如果一个对象嵌套在另一个对象中,或者至少一个是大小为零的子对象并且它们属于不同类型,则两个具有重叠生命周期且不是位域的对象可能具有相同的地址;否则,它们具有不同的地址并占用不相交的存储字节。
声明为的空类型的成员[[no_unique_address]]
大小为零,但具有相同类型使得这不可能。
事实上,仔细想想,试图通过嵌套来隐藏空类型仍然违反了唯一标识规则。考虑你的Wrapper
情况Z1
。给定 a z1
which 是 的一个实例Z1
,很明显z1.e1
和z1.e2
是具有不同类型的不同对象。但是,z1.e1
不嵌套在z1.e2
其中,反之亦然。虽然它们有不同的类型,(Empty&)z1.e1
并且(Empty&)z1.e2
不是不同的类型。但它们确实指向不同的对象。
并且根据唯一身份规则,它们必须具有不同的地址。因此,即使e1
和e2
名义上是不同的类型,它们的内部也必须遵守针对同一包含对象中的其他子对象的唯一标识。递归。
无论您如何尝试,您想要的在 C++ 中都是不可能的。
推荐阅读
- scalability - SQS 如何确定每条消息的物理存储位置?
- python - 如何遍历列表?
- java - WebView 进度条仅在页面加载时首次显示。我如何设置每次?
- python-3.x - 如何在 Yellowbrick、micoro avg 和 macro avg 中更改 ROCAUC 中图例的字体大小和位置。如何使两条线不同?
- perl - 有关 CGI 重定向的一般信息
- bash - 在后台运行进程,直到在 bash 脚本中停止
- php - 数据未插入表,数据库连接没有错误
- windows - 使用 WinSCP 和批处理文件在 SFTP 服务器上创建文件夹(当它不存在时)
- keras - 如何在 keras 中获取批次中每个样本的损失?
- amazon-s3 - ValueError: Error when checking target: expected dense_2 to have shape (10,) but got array with shape (9,)