【问题标题】:Default constructor expression and lvalues默认构造函数表达式和左值
【发布时间】:2020-04-13 06:48:54
【问题描述】:

我和我的 C++ 同事遇到了一个奇怪的结构:

struct A { int i; };
void foo(A const& a);

int main() {
  foo(A() = A{2}); // Legal
}

A() = A{2} 表达式完全让我们感到困惑,因为它似乎将 A{2} 分配给了一个临时的、默认构造的对象。但请在编译器资源管理器 (https://gcc.godbolt.org/z/2LsfSk) 中查看。它似乎是一个法律声明(受 GCC 9 和 Clang 9 支持),如下声明:

struct A { int i; };

int main() {
  A() = A{2};
  auto a = A() = A{3};
}

因此,在某些情况下,A() 似乎是一个左值。还是这里发生了其他事情?希望得到一些解释,最好是对 C++17 标准的引用。


更新:@Brian 发现这是 assigning to rvalue: why does this compile? 的副本。但如果有人能在 C++ 标准中找到适当的参考,我将不胜感激。

【问题讨论】:

  • @Brian 是重复的吗? int() = 2; 也是对右值的赋值,但编译器不允许这样做。那么是什么让用户定义的类型与众不同呢?
  • 副本解释了这一点。如果 LHS 是一个类,那么赋值操作调用operator=。如果 LHS 是非类,则使用内置运算符,它需要一个左值。
  • @Brian,很好,但副本没有指定相关的语言标准部分......这就是我要求的。
  • 好的。我重新打开了这个问题。

标签: c++ language-lawyer c++17 rvalue copy-assignment


【解决方案1】:

A{} 始终是每个[expr.type.conv] 的右值

1 A simple-type-specifiertypename-specifier 后跟括号可选 expression-listbraced-init-list(初始化程序)在给定初始化程序的情况下构造指定类型的值。 如果该类型是推导类类型的占位符,则在本小节的其余部分中,它将被重载决议选择的函数的返回类型替换为class template deduction
2 如果初始值设定项是带括号的单个表达式,类型转换表达式等价于对应的cast expression。 否则,如果类型是 cv void 并且初始化程序是 (){}(在包扩展之后,如果有的话),则表达式是指定类型的纯右值,不执行初始化. 否则,表达式是指定类型的纯右值,其结果对象为direct-initialized,带有初始值设定项。 如果初始化器是带括号的可选expression-list,则指定的类型不应是数组类型。

强调我的

这些工作在这里的原因是标准中没有任何内容阻止它工作。

对于像int 这样的内置类型,有[expr.ass]/1

赋值运算符 (=) 和复合赋值运算符都从右到左分组。都需要一个可修改的左值作为左操作数;它们的结果是一个引用左操作数的左值。

所以这会阻止你做int{} = 42;。不过,本节不适用于课程。如果我们查看[class.copy.assign] 并没有说需要左值,但第一段确实说明了

用户声明的复制赋值运算符 X​::​operator= 是类 X 的非静态非模板成员函数,只有一个 X、X&、const X&、volatile X& 或 const volatile X& 类型的参数

这意味着

A{} = A{2};

其实是

A{}.operator=(A{2})

在右值类对象上这样做是合法的,因为您的类的默认 operator = 没有 ref-qualifier 来阻止它在右值上被调用。如果你添加

A& operator=(const A& a) & { i = a.i; }

A,而不是使用默认的赋值运算符然后

A{} = A{2};

将不再编译,因为 operator= 现在仅适用于左值。

【讨论】:

  • 谢谢。关闭。我想我刚刚找到它--8.2.1[basic.lval],第 2 段。
  • @KyleKnoepfel 添加了该位,因此您对每个位都有标准参考。
  • @KyleKnoepfel [basic.lval] 只谈论 Zvalues 的属性,但没有说明哪些表达式是 lvalues/xvalues/prvalues。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-05
  • 1970-01-01
  • 1970-01-01
  • 2016-03-24
  • 1970-01-01
  • 2011-06-18
相关资源
最近更新 更多