【问题标题】:why error lvalue required as left operand does not exhibit for strings?为什么左操作数所需的错误左值不会出现在字符串中?
【发布时间】:2020-02-28 18:08:18
【问题描述】:

在下面的代码 sn-p 中,为什么行 2 + 3 = 5 语句给出错误但下一个分配给字符串连接的语句编译成功?

#include <string>

int main() {                                                                                                                                                  
   2 + 3 = 5;   //  Error: lvalue required as left operand of assignment                                                                                                                                             
   std::string("2") + std::string("3") = std::string("5");  // Compiles successfully. why?                                                                                                 
   return 0;                                                                                                                                                 
}

我的理解是表达式std::string("2") + std::string("3") = std::string("5") 的左侧将产生临时的rvalue。这意味着我分配给rvalue - 就像2 + 3 = 5。所以它也应该给出lvalue required as left operand of assignment 错误。但事实并非如此。

【问题讨论】:

  • 简化 std::string("3") = std::string("5"); 仍然可以编译
  • 刚刚检查了大多数标准容器,其中没有一个删除了operator= 的右值版本,例如basic_string&amp; basic_string::operator=( CharT ch ) &amp;&amp; = delete; 不适用于任何容器。所以我想这是一个有意识的决定。

标签: c++ assignment-operator rvalue


【解决方案1】:

说明

对于类类型,赋值是通过复制和移动赋值运算符实现的。 std::string 是一个类,所以

std::string("2") + std::string("3") = std::string("5")

只是

的语法糖
(std::string("2") + std::string("3")).operator=(std::string("5"))

operator= 是一个成员函数。通常,可以在左值和右值上调用成员函数。因此,这个表达式是有效的。

标准参考

对于非重载operator=(即对于int):[expr.ass]/1

赋值运算符 (=) 和复合赋值运算符 所有组从右到左。都需要 一个可修改的左值作为它们的 左操作数并返回一个引用左操作数的左值。 [...]

对于过载operator=(对于std::string):[expr.ass]/4

如果左操作数是类类型,则类应该是完整的。 对类对象的赋值由复制/移动赋值运算符定义([class.copy],[over.ass])。

(强调我的所有)

【讨论】:

  • 更奇怪的是,赋值返回的是左值,而不是 xvalue。
  • @DavisHerring 是的。我想说std::string 一开始就不是为右值赋值而设计的,所以它不会影响传播值类别。
  • @L.F.据我所知,这是所有标准容器
  • @UnSat:……它的标识和存储是临时物化的,用于为(隐式)函数调用制作 xvalue 对象表达式。但是说“它返回std::string&amp;,所以它是一个左值”要容易得多。
  • @UnSat 这是价值类别的简化视图。对于一些简单的场景,这可能是一个有用的类比,但不要将其视为定义。
【解决方案2】:

该规则仅适用于内置类型的对象,例如 int

它不适用于课程。

该规则可能被认为对于类来说过于严格,其运算符可能会被重载以执行各种操作……或者在 C++ 出现时可能被认为过于严格,但破坏旧的 C 代码是不行的通过放宽内置规则。

不管怎样,你加法的结果实际上是一个左值,因为当你从一个函数返回一个左值引用,比如std::string&amp; 时,你会得到这个结果。尽管加法的两个操作数都是右值表达式和临时对象。这里可能有点令人惊讶,there's a proposal to do better at "propagating value category" 在这种情况下,现在语言为我们提供了这样做的工具。

【讨论】:

  • 加法的结果(+ 表达式是一个operator+ 调用)是一个右值。赋值的结果是一个左值。
  • @aschepler 嗯guess you're right。我从没想过内置操作的规则会适用于重载的操作。事实上,我敢肯定最近有一个案例,其中一条这样的规则显然没有。我闻到不一致的味道
  • 它没有使用内置运算符的规则。添加两个字符串的结果是一个右值,因为使用的operator+ 函数返回一个std::string(不是引用)。
  • @aschepler .... 哦,是的。 ? 为什么我在想复合作业?我需要一个假期。
猜你喜欢
  • 2011-12-20
  • 2011-03-04
  • 2021-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-10
  • 1970-01-01
相关资源
最近更新 更多