432,483 Members | 1,052 Online
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 432,483 IT Pros & Developers. It's quick & easy.

# Confused about the comma operator

 P: n/a I came upon the idea of writting a logging class that uses a Python-ish syntax that's easy on the eyes (IMO): int x = 1; double y = 2.5; std::string z = "result"; debug = "Results:", x, y, z; The above example outputs: Results: 1 2.5 result The implementation uses a template comma operator and a template operator= to kick things off. Here is a very minimal implementation: struct Value { template Value(const T& x) { std::cout << x << ' '; } template Value operator,(const U& y) { return Value(y); } }; struct Log{ template Value operator=(const T& x) { return Value(x); } } debug; It works, but now that I think about it, I'm not sure WHY it works. Does it work because the operator= has higher precedence than the comma operator, so the compiler sees it like this: (debug = "Results:"), x, y, z; Of course operator= returns a Value object which displays "Result" and (thanks to the template comma operator) keeps the chain going in the normal left-to-right evaluation order? If this is the case, then I find it counter-intuitive because the type and value of an expression in the form (e1,e2) is e2. I find this behavior a bit surprising and inconsistent: void print(int i) { std::cout << i << '\n'; }; int w; w = 1, 2; // w = 1 print(w); // prints 1 print((1,2)); // prints 2 Jul 22 '05 #1
5 Replies

 P: n/a On Sun, 11 Apr 2004 15:38:18 -0400, Derek wrote: It works, but now that I think about it, I'm not sureWHY it works. Does it work because the operator= hashigher precedence than the comma operator, so thecompiler sees it like this: (debug = "Results:"), x, y, z; Right. Of course operator= returns a Value object whichdisplays "Result" and (thanks to the template commaoperator) keeps the chain going in the normalleft-to-right evaluation order? Sure. If this is the case, then I find it counter-intuitivebecause the type and value of an expression in the form(e1,e2) is e2. I find this behavior a bit surprisingand inconsistent:void print(int i){ std::cout << i << '\n'; };int w;w = 1, 2; // w = 1print(w); // prints 1print((1,2)); // prints 2 The evaluation order of the comma operator is fixed as left-to-right; this is more than a simple associativity rule, as in the case of, say, the additive operators where a + b give the compiler the freedom to evaluate either a or b first (or both simultaneously). Since the order of evaluation of the comma operator /is/ fixed, it makes the most sense to have the value of the result be the value of the last operand evaluated; otherwise the compiler might have to do extra work to "push" the value of the left-most operand before evaluating the rest, and then "pop" that value afterwards. -leor -- Leor Zolman --- BD Software --- www.bdsoft.com On-Site Training in C/C++, Java, Perl and Unix C++ users: Download BD Software's free STL Error Message Decryptor at: www.bdsoft.com/tools/stlfilt.html Jul 22 '05 #2

 P: n/a Leor Zolman wrote: Since the order of evaluation of the comma operator /is/ fixed, it makes the most sense to have the value of the result be the value of the last operand evaluated; otherwise the compiler might have to do extra work to "push" the value of the left-most operand before evaluating the rest, and then "pop" that value afterwards That makes sense and I find the left-to-right behavior of the comma operator perfectly sensible. I just think that the fact that it has the lowest precedence of all operators can lead to unexpected behavior. To repeat my simple example: int x; x = 1,2; // x is 1 I would expect x to be 2 because of the left-to-right evaluation of the comma operator, but here op= takes precedence. Jul 22 '05 #3

 P: n/a On Sun, 11 Apr 2004 18:41:35 -0400, Derek wrote: Leor Zolman wrote: Since the order of evaluation of the comma operator /is/ fixed, it makes the most sense to have the value of the result be the value of the last operand evaluated; otherwise the compiler might have to do extra work to "push" the value of the left-most operand before evaluating the rest, and then "pop" that value afterwardsThat makes sense and I find the left-to-right behaviorof the comma operator perfectly sensible. I justthink that the fact that it has the lowest precedenceof all operators can lead to unexpected behavior. Torepeat my simple example:int x;x = 1,2; // x is 1I would expect x to be 2 because of the left-to-rightevaluation of the comma operator, but here op= takesprecedence. One thing Java got right, IMHO, was to limit the use of the comma operator to the "init" and "incr" portions of for loops. This would have eliminated an awful lot of grief wrt the comma operator's precedence in C and C++. I learned early on to always think of it as "the lowly comma operator," as a mental cue to not lose track of its precedence whenever I encountered its use in expressions other than as part of the aforementioned 'for' loop constructs. It took the emergence of Stupid Template Tricks such as yours (and I use the term affectionately, /not/ disparagingly) and Thorsten Ottosen's initialization library: http://www.codeproject.com/vcpp/stl/PGIL.asp?print=true to finally give the comma operator some good reason for existence other than "for" loop management. -leor -- Leor Zolman --- BD Software --- www.bdsoft.com On-Site Training in C/C++, Java, Perl and Unix C++ users: Download BD Software's free STL Error Message Decryptor at: www.bdsoft.com/tools/stlfilt.html Jul 22 '05 #4

 P: n/a Leor Zolman wrote: One thing Java got right, IMHO, was to limit the use of the comma operator to the "init" and "incr" portions of for loops. This would have eliminated an awful lot of grief wrt the comma operator's precedence in C and C++. [ ... ] to finally give the comma operator some good reason for existence other than "for" loop management. I have found some other occasional uses for it: 1. In preprocessor macros, to enable them to act like functions with a return value (and to avoid the do..while(0) construct) 2. To return an error code and also perform error logging, concisely: if (FAILED(foo())) return do_log(whatever), ERR_FOO_FAILED; Admittedly these are C-based uses that can probably be superseded by more natural C++ constructs. Also, in the same vein as 2, sometimes if my actions to perform in a block after an "if" or "else" are concise, or conceptually one action that requires 2 statements, I will write "a, b;" instead of going to 4 lines by using curly braces and a semicolon. Jul 22 '05 #5

 P: n/a Old Wolf wrote: I have found some other occasional uses for it: 1. In preprocessor macros, to enable them to act like functions with a return value (and to avoid the do..while(0) construct) Using the preprocessor for this kind of thing is almost always VERY BAD. 2. To return an error code and also perform error logging, concisely: if (FAILED(foo())) return do_log(whatever), ERR_FOO_FAILED; This is silly. No, on second thought it is stupid. if (FAILED(foo)) { do_log(whatever); return ERR_FOO_FAILED; } Also, see below. Admittedly these are C-based uses that can probably be superseded by more natural C++ constructs. Also, in the same vein as 2, sometimes if my actions to perform in a block after an "if" or "else" are concise, or conceptually one action that requires 2 statements, I will write "a, b;" instead of going to 4 lines by using curly braces and a semicolon. What is with this whole "It's more concise (i.e., better) if I squeeze it all on one line!" thing that so many programmers seem to have a religious belief in? If you MUST do this kind of junk: if (FAILED(foo)) { do_log(whatever); return ERR_FOO_FAILED; } There! It's better than your two line thing 'cause it's only one line right? Jul 22 '05 #6

### This discussion thread is closed

Replies have been disabled for this discussion.