views:

200

answers:

6

Have a look at these function signatures:

 class Number {
 public:
   Number& operator++ ();    // prefix ++
   Number  operator++ (int); // postfix ++
 }; 

Prefix doesn't take any parameter but postfix does. Why? I thought we can recognize them with different return types.

+5  A: 

You are free to give operator++ any return type you like, so there's not way to distinguish postfix and prefix by that. So the compiler needs some kind of clue.

OTOH, I don't know why this couldn't had been done in syntax only:

//prefix
int& ++operator (); 
//postfix
int& operator++ (); 

After all, mimicking usage in declarations has tradition in C and C++.

P.S. Other posters: This has nothing to do with overloading by return type. postfix and prefix ++/-- are two different names. There is no need to resolve an overload in x++ or ++x, because it's entirely clear which name is meant.

Luther Blissett
is it, might be they could have done it in the way you suggested :)..so Just for the compiler differentiation they write parameter right?another Question, why they made postfix to accept parameter, why not prefix? they could have interchanged right, any specific difference?
Shadow
Dennis Zickefoose
@Shadow: The extra parameter for postfix works as a visual reminder that the action happens of the right hand side..
Luther Blissett
`++x` and `x++` may be different syntactic sugar, but `operator++()` and `operator++(int)` look very much like two overloadings of the same function name to me.
Edmund
"...it's entirely clear which name is meant", unless of course the compiler is of the sound opinion that both `++x` and `x++` mean `x.operator++()`. There is a need for a resolution, and overload resolution is a perfectly reasonable way to do it. There aren't any other operators in C++ that are differentiated by "fixity" alone, so it would be somewhat extravagant and cluttering to alter the `operator` syntax for only two special cases. And the `int` param has no guaranteed value, so I believe the compiler is free to not actually pass anything, thus invoking no extra cost.
Jon Purdy
Overloading couldn't be done as `++operator` because then, to be consistent, you'd have to make all the standard unary operators (+, -, !, *, ~) prefix notation, and then `*operator` would be ambiguous, since `int *operator()` could look like "functional operator returning pointer to int" instead of "pointer dereference operator returning int". Also, the parser is easier to implement (and better at catching errors) if the keyword `operator` always comes first.
Mike DeSimone
@Mike: the ambiguity is the reason. If ++operator where allowed the lexing would be much more difficult (which in this case spells: orders of magnitude slower).
Fabio Fracassi
@Fabio: How does that affect lexing? `operator` and `++` are two different tokens. It shouldn't make a difference for the lexer if the come in either order.
Luther Blissett
@Jon not true. The int parameter is guaranteed to be `0` when invoked by the compiler for processing an expression.
Johannes Schaub - litb
@Luther Blissett, you mean, function overloading should be differentiated only by the parameter type, return type is optional or not?
Shadow
@Luther you are probably right, I mixed something up, and thought that the whole Identifier would be treated as a token. Sorry.
Fabio Fracassi
@Johannes Schaub: Thanks, could you point me to a source for that?
Jon Purdy
+2  A: 

You're not allowed to overload functions purely by return type, so a dummy parameter is necessary to differentiate between two identical looking operator++() operators.

AshleysBrain
A: 

from return type you can't overload a method.

so to distinguish it is needed

org.life.java
+4  A: 

Prefix and postfix ++ are different operators. With the standard Foo operator symbol(Foo &) style declaration there was no obvious way to distinguish the two. Rather than come up with some new syntax like Foo symbol operator(Foo &) which would make it into a special case unlike all the other operators and likely a bit of a pain to parse, the language designers wanted some other solution.

The solution they chose was somewhat bizarre. They noted that all the other 'postfix' operators (i.e. operators that occurred after one of their operands) were actually infix operators that took two arguments. For example, plain old + or -. On this basis the language designers decided that having a random dummy argument would be a good way to distinguish between prefix and postfix ++.

IMHO, it's one of the stranger decisions made as C++ evolved. But there you have it.

And you can't distinguish them based on return type for two reasons.

The first is that functions in C++ cannot be overloaded on return type. You cannot have two functions that have identical names and parameter type lists but different return values.

The second is that method would not be robust or flexible enough to handle all possible implementations of prefix and postfix ++.

For example, you might want a postfix ++ that returned a reference type if the only reason you ever called it was to invoke a side-effect unrelated to the value of the variable you were applying it to. In my opinion, that would be a very bad implementation, but C++ is not about judging what kinds of stupid code you want to write, but about enabling you to write whatever code it is you think appropriate to the situation. And forcing you to use one particular style of return type for prefix ++ and postfix ++ would be contrary to that spirit.

Omnifarious
As a side note, I gleaned this information from "The Design and Evolution of C++" by Bjarne Stroustroup. I would recommend it if you want to really understand why C++ is the way it is. Growing a language by accretion in an environment where backward compatibility is very important leads to a lot of strange things.
Omnifarious
There aren't any really good alternatives, though. You could invent a pseudo-operator (e.g. `operator +++`) that people will forget or get wrong, or add a keyword (e.g. `post operator ++`), or abandon using the operators themselves and use special names instead (e.g. Python's `__add__` and friends). All look worse than the dummy variable.
Mike DeSimone
@Mike: with respect to named operators, I have to disagree. However ugly you might think it is, `operator post_increment()` is much easier to read. `operator subscript` `operator function_call` and `operator cast`, would also get readability boosts. but that's a lot of new keywords.
Dennis Zickefoose
Yes, `operator post_increment` would be much easier to read, but then `post_increment` becomes a reserved word, possibly breaking compilers or other programs which already used that name. Hence Python's "names with leading double underscores are all reserved" convention. See the history of XHTML for an example of why not to cause massive backward compatibility breakage in a new standard.
Mike DeSimone
Also, C and C++ have historically had a strong aversion to keywords: there are very few in those languages, and when they add some (e.g. `static_cast`) there's a lot of pushback, especially from programmers whose native language is not English.
Mike DeSimone
@Mike - Yes, exactly, and that's the decision the people designing C++ made as well. It doesn't make it any less strange. Though I do have to agree with @Dennis about readability. Again, preserving backwards compatibility and designing by accretion leads to strange results sometimes.
Omnifarious
@Mike: You don't have to make `post_increment` a new keyword . If you introduce a new syntax for "explicit" operator names, then you can add a rule like: `'operator' 'explicit' <identifier> (<args>)` where identifier must be one of the explicit operator names (like 'post_increment', 'pre_increment' etc.). From a parsing standpoint, they don't have to be reserved words, because they're only "special" in then `operator explicit` position. This is really easy to implement!
Luther Blissett
@Luther: it might have repercussions if it is at all common to have those phrases used as macro names. Otherwise, you're right.
Dennis Zickefoose
@Luther - Yes, that might work, and it would be, IMHO, the best solution.
Omnifarious
Also, once you have a typedef which reads `typedef int post;` you can write `R operator++(post);` which i think looks not too bad.
Johannes Schaub - litb
+1  A: 

Straight from Bjarne's mouth:

This may be both too cute and too subtle, but it works, requires no new syntax, and has a logic to the madness. Other unary operators are prefix and take no arguments when defined as member functions. The "odd" and unused dummy int argument is used to indicate the odd postfix operators. In other words, in the postfix case, ++ comes between the first (real) operand and the second (dummy) argument and is thus postfix.

These explanations are needed because the mechanism is unique and therefore a bit of a wart. Given a choice, I would probably have introduced the prefix and postfix keywords, but that didn't appear feasible at the time. However, the only really important point is that the mechanism works and can be understood and used by the few programmers who really need it.

By the way, in my opinion, only prefix ++ should be overloadable by the programmer, and postfix ++ should be automatically generated by the compiler. Does anyone agree with me?

FredOverflow
Does anyone agree with me? - `#include <boost/operators.hpp>`
UncleBens
Not the way the language is currently set up, no. I do think it would be neat if, after 0x, we could default operators and let the compiler build them from other operators you do define.
Dennis Zickefoose
A: 

If I had my druthers, postincrement and many sequence-point operators would be split into two or three parts; in the case of postincrement, a statement like "a=(b++ + c++);" would be effectively translated as "a=postinc1(b)+postinc1(c); postinc2(b); postinc2(c);"; the second part of post-increment would be a void function. In actual implementation, the postinc2() calls should often likely occur while some other results are sitting on the evaluation stack; that shouldn't be too hard for a compiler to implement.

In the case of "&&" or "||", the first part of the operator would just operate on the left operand; if it returned non-zero (for &&) or non-zero (for ||), then the second part would operate on both operands.

In the case of "?"/":", the first part of the operator would operate on just the first operand. If it returned non-zero, the second part would operate on the first and second parameters; otherwise the third part would operate on the first and third parameters.

Do any languages do anything like that? It seems odd that C++ allows operators to be redefined in ways that break sequencing behavior, but does not allow them to be redefined in ways that preserve it.

supercat