4

The posts What can I use instead of the arrow operator, `->`? and Arrow operator (->) usage in C state

The following two expressions are equivalent:

x->y
(*x).y

But this does not appear to always be true when taken as a mathematical equivalence.

Why does g++ throw an error when replacing

a->b->c

with

a->(*b).c

?

It seems the above equivalence is not always replaceable. Therefore, I think the term "equivalent" is a bit misleading.

Also, I am not referring to any sort of overloading in this question.

Community
  • 1
  • 1
Tommy
  • 12,588
  • 14
  • 59
  • 110
  • By the way, you’re wrong in this particular regard (see answers) but it’s true in general that `a->b` and `(*a).b` are *not* necessarily equivalent, since `->` and `*` can be overloaded for your own classes. They *are* completely equivalent when `a` is of pointer type, however (or when `operator ->` and `operator *` are overloaded correctly). – Konrad Rudolph Jul 16 '12 at 19:34
  • Konrad, my point is we have to be careful about the term "completely equivalent". When I read that phrase, it reads "any instance of the first can be replaced with the second". It seems that in this case, equivalence is dependent upon the order of operations. – Tommy Jul 16 '12 at 19:49
  • They *are* completely equivalent. But you still need to obey the rules of precedence when doing replacements. You cannot just do textual replacements. After all, in mathematics “x + x” and “2 * x” are completely equivalent (they are equal for all values of x), yet when you ignore the rules of mathematics and replace the first by the second in the mathematical expression “x + x / 2” you get a wrong result (because x + x / 2 ≠ 2 * x / 2). – Konrad Rudolph Jul 16 '12 at 20:02
  • But (x + x) / 2 is equivalent. However, a->((*b).c) also seems to fail. – Tommy Jul 16 '12 at 20:09
  • 2
    Because now you’re violating the grammar rules of C++. `->` must be followed by an identifier, not an expression. That’s still the same as in mathematics. Otherwise you get joke equations like this one: http://i.imgur.com/JLPF2.jpg – Konrad Rudolph Jul 16 '12 at 20:22

4 Answers4

16

You've got the associativity rules wrong. a->b->c is (a->b)->c, not a->(b->c), so it becomes (*(a->b)).c (and then (*((*a).b)).c).

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
8

Because you're not replacing the operators correctly. It should be:

(*(a->b)).c

You're treating your expression as a->(b->c) when you should be treating it as (a->b)->c

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
2

You're doing the replacement incorrectly.

a->b->c is equivalent to (*(a->b)).c.

a->(*b).c doesn't make sense for a number of reasons. b is not a pointer you can dereference (the pointer is a->b). Additionally, even if it were, using the dereferenced pointer in the context of a field of a would not make sense.

Eric Finn
  • 8,629
  • 3
  • 33
  • 42
1

The problem you are seeing is an issue with the precendence of the different operators, you should use: (*(x->y)).z (The operands to the second -> are (x->y) and z). But that has already been answered before.

It is important to note, however, that the equivalence is only true for pointers, and that the properties of both operators when overloaded are completely different. The operator-> has very strange semantics in the language, in the sense that it does not represent a single operation, but can represent multiple applications of operator-> until the overloaded operator yields a raw pointer, at which point it will perform one last application that is equivalent to dereference plus access (i.e. only for this last application, a->b is equivalent to (*a)->b.)

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489