提问者:小点点

具有引用成员的结构是否具有唯一的对象表示形式?


这个回答引出了下面的问题。

假设我们有一个简单的

struct S {
    int& i;
}

在内部(至少在GCC和Clang中)s只包含一个指向int的指针,并且

static_assert(sizeof(int*) == 8);
static_assert(sizeof(S)    == 8);

s是否具有唯一的对象表示形式? GCC和Clang不同意*:

static_assert( std::has_unique_object_representations_v<int*>);
static_assert(!std::has_unique_object_representations_v<S>);    // GCC
static_assert( std::has_unique_object_representations_v<S>);    // Clang

哪个编译器在这里,为什么?

*idclev 463035818注意到GCC和Clang之间的分歧。


共3个答案

匿名用户

请注意,Clang明确地根据Richard Smith的评论选择他们的方法,即使知道GCC拒绝了(在OP上下文中)std::has_unique_object_representations_v,并指出GCC的这种行为是可能的bug[强调我的]:

erichkeane引用不能简单地复制,因此它们将防止结构具有唯一的对象表示。

在我看来这是错误的行为。 如果两个结构具有绑定到相同对象的引用,那么它们具有相同的对象表示形式,因此结构确实具有唯一的对象表示形式。

埃里奇基恩我不是这么想的。。。 我将注意到GCC拒绝在其实现中引用,但这可能是他们方面的一个bug。

rsmith[...] 所以我认为引用和指针一样,当被认为是类类型的对象的成员时,应该始终被认为具有唯一的对象表示。 (但是__has_unique_object_representations(T&;)仍然应该返回false,因为T&;不是一个简单的可复制类型,即使包含T&;的类可能是。)

正如@idclev 463035818所指出的,Clang和GCC都同意S是简单可复制的,这意味着他们的分歧在于两个具有相同值的(简单可复制的)类型S的对象是否具有相同的对象表示; @Eerorika的答复通过参考有关标准段落表明,海湾合作委员会驳回这项索赔是错误的。

匿名用户

首先,引用不是对象。 对象在[intro.object]中指定,引用在[dcl.ref]中指定。

子对象是对象([Intro.Object])。 因此,引用成员不是子对象,因此只包含引用成员(没有基)的类没有子对象(即使它有数据成员)。

[meta.unary.prop]

当且仅当:

  • T是可以复制的,
  • 任意两个具有相同值的类型T的对象具有相同的对象表示,其中,如果数组或非并集类类型的两个对象各自的直接子对象序列具有相同的值,则认为它们具有相同的值,...

子对象的序列是空的,因此等于另一个空序列,因此满足第二个要求。

s是否可以简单地复制?

static_assert(std::is_trivially_copyable_v<S>);

在Clang和GCC中传递。 因此,GCC是错误的,因为这两个要求都得到了满足,因此s必须具有唯一的对象表示。

另一件奇怪的事情是,根据MSVC的说法,s是不可复制的。 因此,尽管它同意GCC关于缺乏唯一表示的观点,但根据has_unique_object_representations的规则,它是一致和正确的。 那么,关于琐碎的可复制性,哪一个是正确的呢?

[class.copy.ctor]

如果类X的复制/移动构造函数不是用户提供的,并且如果:

  • 类X没有虚函数([class.virtual])和虚基类([class.mi]),
  • 为复制/移动每个直接基类子对象而选择的构造函数是微不足道的,并且
  • 对于X的每个属于类类型(或其数组)的非静态数据成员,选择用于复制/移动该成员的构造函数是微不足道的;

这些都是满意的。 因此,S有一个简单的复制/移动构造函数。

[class.prop]

简单可复制的类是这样的类:

  • 至少具有一个合格的复制构造函数,移动构造函数,复制赋值运算符或移动赋值运算符([special],[Class.copy.ctor],[Class.copy.Assign]),
  • 其中每个合格的复制构造函数,移动构造函数,复制赋值运算符和移动赋值运算符都是微不足道的,并且
  • 具有一个简单的,未删除的析构函数([class.dtor])。

所有这些都是满意的,因此s是微不足道的可复制的,而MSVC是错误的。

匿名用户

s是可复制的,因为它没有类类型的成员,也没有用户声明的成员函数。 这一点没有争议; 当idclev 463035818 poitns out时,两个编译器都同意std::is_trivially_copyable_v==true

因此问题被简化为两个相同的S对象是否按位相同。 由于两个实现都选择将引用表示为指针(一个有效的选择),std::HAS_UNIQUE_OBJECT_REPresentations_V必须匹配std::HAS_UNIQUE_OBJECT_REPresentations_V。 因此,海合会错了。