【问题标题】:Is there any good reason C++ doesn't permit doubling the -> operator?C++ 不允许加倍 -> 运算符有什么好的理由吗?
【发布时间】:2014-06-24 08:20:58
【问题描述】:

在 C++ 中,您可以将间接运算符加倍:

vector<unique_ptr<string>> arr{make_unique<string>("Test")};
cout << **arr.begin() << endl;

但是你不能把解引用操作符加倍:

cout << arr.begin()->->c_str() << endl;

相反,您必须接受这个 (IMO) 不太清晰的替代方案:

cout << (*arr.begin())->c_str() << endl;

operator-&gt; 是一个返回指针类型的一元运算符,因此能够将它们链接起来似乎很自然。这种限制有什么好的理由吗?是否有一些我没有看到的解析困难?

编辑

在 5.2.5/3 中,C++ 标准规定:

如果 E1 的类型是“指向 X 类的指针”,那么表达式 E1->E2 是 转换为等价形式 (*(E1)).E2

我只是希望它被指定为:

如果 E1 的类型是“指向 X 类的指针”,那么表达式 E1-> 是 转换为等价形式 (*(E1))。

实际上包含 E1 和 E2 的定义似乎是相反的,因为重载的 operator-&gt; 不是二元运算符。

【问题讨论】:

  • &lt;&lt; 与 2*&lt; 不同...
  • 那将是一些完全令人困惑的语法
  • 你不能“加倍”*。您可以应用一次,然后再将其应用到结果中。 -&gt; 也是如此,例如你可以做it-&gt;first-&gt;foo-&gt;-&gt; 将是一个全新的运营商,其收益甚至比 -&gt; 已经拥有的更少。
  • @anishsane 确实,但在语法上这很愚蠢。 2个相同的字母是坏的。有人应该给出“a->b”的推理是“(*a).b”的简写,所以 ->-> 没有意义
  • OP 这是一篇有用的文章:boredzo.org/pointers

标签: c++


【解决方案1】:

注意:

(*a).b
a->b

都是一样的

所以

a->->b
(*a)->b
(*(*a)).b

作为操作员也可以,但这不符合-&gt; 的精神,精神是访问结构中指向的东西。我宁愿输入a-&gt;b 而不是(*a).b

因此,虽然(*a)-&gt;b 没有技术原因告诉您“a 是指向具有b 的结构的指针的指针”,而a-&gt;b-&gt;c 完全a-&gt;-&gt;b 不同,尽管它们看起来很相似。

【讨论】:

  • a->->b 将是 (*(*a).).b 请参阅下面的答案。
  • @DutchOven 我们可以定义一个以上的情况,它会起作用。你也在看operator-&gt;
  • C+ 标准 5.2.5/3:“如果 E1 的类型为“指向 X 类的指针”,则表达式 E1->E2 被转换为等价形式 (*(E1)).E2 ;"
  • @AlecTeal,我们可以定义它,在这种情况下它将是一个全新的运算符(就像+++ 的不同之处。)我们也可以将--&gt; 定义为“取消引用”两次,获得成员一次”,这是所需的能力。但正如我在下面所说的,并且@staticx 确认,箭头代表*.(点),与所需的行为不匹配。
  • 或者我们可以将其定义为“如果 E1 的类型为“指向类 X 的指针”,则表达式 E1-> 将转换为等效形式 (*(E1))。它会像我描述的那样工作。
【解决方案2】:

这里是一个不太技术性的解释。

-&gt;*(*someptr).memberfunc(). 的简写。因此这可以表示为someptr-&gt;memberfunc()

在您的示例中,两个-&gt;(*(*arr.begin()).).c_str() 相同。注意额外的点。这没有意义,也无法编译,因为 .是二元运算符,* 是一元运算符。因此,您将有一个“额外的”点。你真的想要两个*,只有一个.。像你一样使用一个-&gt;和一个*

-&gt; 表示“取消引用并获得成员”。您想取消引用两次,并获得一个成员一次,所以双 -&gt; 不是您想要的。

【讨论】:

  • 我猜你的意思是(*(*arr.begin()).).c_str())。您缺少 begin() 上的括号,并且在 c_str 之后有一个额外的 *。假设这就是您要输入的内容,对我来说,->-> 是它的简写似乎是完全合理的。
  • 谢谢。我添加了缺少的括号并删除了虚假的 *.
  • 并添加了最后一段。
  • 只要一个类不重载这些运算符,那么它们在功能上是等效的
  • 但这真的意味着“取消引用并获得会员”吗?当您在一个类中定义自己的operator-&gt; 时,它是一个一元运算符。它不知道任何成员。它只是返回一个指针。
【解决方案3】:

如果我理解正确,您可以通过更好的设计获得您正在寻找的行为。

如果提供稍微复杂一点的行为,取消引用运算符实际上并不能像从指针中检索值的运算符那样真正起作用。

-&gt; 操作符的业务逻辑很明显是illustrated here,它也在扩展herehere,你可以鸟瞰指针相关的操作符here

您很容易猜到,如果您有 T-&gt;t,则可以使用向下钻取行为,假设您已正确设计和定义 T 及其自己的 -&gt; 运算符。

这是一个可以轻松为您的应用程序带来一些多态行为的解决方案。

【讨论】:

  • 我不确定重载operator-&gt; 以自动向下钻取真的是“更好的设计”。事实上,即使是那个答案的作者也声称这样的设计“让小猫哭了”。当您使用不是自己编写的库时,它也不提供解决方案。 vector> 现在真的不是那么罕见了。
  • @RickYorgason “更好的设计”是与此示例相关的声明,在我看来,C++ 中的指针应该始终是最后的资源。在 C++ 中还有其他概念,例如更适合高级语言的迭代器和流,再加上最新的 C++11 功能,您真的没有任何好的借口在 C++ 中使用指针。所以是的,它“让小猫哭泣”主要是因为指针不提供真正的高级语义或任何高级概念,它们可能难以调试或显示一些细微的错误,例如任何与高级语言混合的低级概念。
  • 你真的认为 unique_ptr 的向量是一个糟糕的设计吗?否则您将如何存储多态对象列表?迭代器和智能指针将与原始指针一样受益。
猜你喜欢
  • 1970-01-01
  • 2012-10-30
  • 1970-01-01
  • 2018-05-17
  • 1970-01-01
  • 1970-01-01
  • 2011-07-17
  • 1970-01-01
相关资源
最近更新 更多