Which comes first?

Pages: 123
The first example is still an expression to me
Nope. Initialization syntax doesn't form an expression, it forms a list of comma-separated expressions. Like this (BNF follows):
1
2
3
4
5
6
7
initialization: type list ';' ;

list: list_item
    | list ',' list_item ;

list_item: identifier
         | identifier '=' expression ;


From the way Disch explained it, it sounded like no possible way it could be defined to always be true. Is there a variation of that that isn't defined?
For example, a++ + a++ is undefined. There can't be more than one operation with side effects performed on a single variable without a sequence point in between them. For example, && and , introduce sequence points, but + doesn't.
@JLBorges
Yes, you're right, just looking at it from a logical stand point. But the reason I say that it's a template parameter is because of the ... (I don't remember the name for it) argument(s). A template, must accept certain things, and there is no limit to what they can be, as long as they follow the template, i.e. <T,T,C,T> will accept any parameters in that order as long as it's of data type T, T, C, T. can be int, int, char, int, or whatever floats your boat.

@Peter87
I assume you mean something more along the lines of this:
1
2
3
4
5
6
7
8
9
10
11
12
int a = 0;

a ++ + ++ a * ++ a;

// Evaluates to

(a ++) + ((++ a) * (++ a));
(a ++) + ((1) * (++ a));
(a ++) + ((1) * (2));
(2) + ((1) * (2));
(2) + (2);
(4);


Just because I wanted to see what it turned out, using my logic, before I compiled it.

Complete code:
1
2
3
4
5
6
7
8
9
#include <iostream>

int main() {
   int a = 0;

   std::cout << (a ++ + ++ a * ++ a);
   
   return 0;
}
6


Not what I expected by any means, but makes me reconsider my logic (possibly that variables, without parenthesis, are evaluated left to right, regardless of operator in between them). Which, looking at it that way, would give me a result of 6.
helios wrote:
Nope. Initialization syntax doesn't form an expression, it forms a list of comma-separated expressions. Like this (BNF follows):

That's exactly how I meant to word it, you just happened to word it better. Expression is the correct word, however, using commas to declare an object, and separate others, you're also declaring those objects too. The reason I posted the example of the auto data type is because it was something I, naively, did already. I've also attempted this before, being dumb:
1
2
int a = 0;
int b = 1, a = 2;

I say they're an expression (again the wrong word, but broken down, I look at it like this:
1
2
3
4
int (a = 0);
int (b = 1, a = 2);
// int (b = 1);
// int (a = 2); 

And suddenly it makes sense. Looking at it from any other standpoint makes it seem like the above isn't true, but I feel each variable is evaluated at it's turn. Similarly:
1
2
3
4
int a = (b, c, d);
// int a = b;
// int a = c;
// int a = d; 
Volatile Pulse wrote:
int a = 0;

a ++ + ++ a * ++ a;

// Evaluates to

No, it does not evaluate to what you wrote, or to anything else meaningful. This expression is undefined.
Last edited on
Volatile Pulse wrote:
1
2
int a = 0;
int b = 1, a = 2;

I say they're an expression (again the wrong word, but broken down, I look at it like this:

1
2
3
4
int (a = 0);
int (b = 1, a = 2);
// int (b = 1);
// int (a = 2);  

Since the former is illegal, I don't see how it could translate to the latter. Then again, I'm not sure what you're saying with the latter since it is also illegal syntax.


Similarly:
1
2
3
4
int a = (b, c, d);
// int a = b;
// int a = c;
// int a = d;  

More accurately:
1
2
3
b;
c;
int a = d ;

or
1
2
3
4
int a ;
b ;
c ;
a = d ;


In the case of int a = b, c, d; it could be rewritten as:
1
2
3
int a = b ;
c ;
d ;


[Edit: Making the assumption that b, c, and d were previously defined.]
Last edited on
cire wrote:
In the case of int a = b, c, d; it could be rewritten as:
1
2
3
int a = b ;
c ;
d ;



[Edit: Making the assumption that b, c, and d were previously defined.]

Actually, b must be declared previously, and c and d can't have previously been declared in scope.

Based on what you said, this must at least be true:
1
2
3
4
5
6
7
8
#include <iostream>

int main() {
   int b, c, d;
   int a = b, c, d;
   
   return 0;
}


Errors:
C:\Programming\Test3\main.cpp||In function 'int main()':|
C:\Programming\Test3\main.cpp|5|error: redeclaration of 'int c'|
C:\Programming\Test3\main.cpp|4|error: 'int c' previously declared here|
C:\Programming\Test3\main.cpp|5|error: redeclaration of 'int d'|
C:\Programming\Test3\main.cpp|4|error: 'int d' previously declared here|
C:\Programming\Test3\main.cpp|4|warning: unused variable 'c' [-Wunused-variable]|
C:\Programming\Test3\main.cpp|4|warning: unused variable 'd' [-Wunused-variable]|
C:\Programming\Test3\main.cpp|5|warning: unused variable 'a' [-Wunused-variable]|
||=== Build finished: 4 errors, 3 warnings (0 minutes, 2 seconds) ===|


Which takes me back to the way the comma operator works. When you declare variable x, all variables on that line (separated by a comma) are also declared. That's why the first thing you quoted isn't legal. a was previously declared, this line int b = 1, a = 2; attempts to redeclare it, which is illegal. That's why I said the comma in this situation is an operator and not a separator. It operates the declaration of variables, or just expressions (it depends on if there is a data type to declare a variable).

It's getting a little confusing but that's why I used parenthesis. Any time you have a declaration, everything after the data type is in parenthesis (evaluated and broken apart) before actually being declared.

This is legal:
1
2
int b = 5;
int a = b;


However, this is not:
1
2
int b = 5;
int a = 2, b = 3;


Looking at it, everything after the data type is broken down:
1
2
3
int b = 5;
int a = 2;
int b = 3;


Now it's clear.

Sorry, not trying to make anyone upset or anything, I love debates, discussions, etc. I just want to make sure we're all on the same page.

cire wrote:
Since the former is illegal, I don't see how it could translate to the latter. Then again, I'm not sure what you're saying with the latter since it is also illegal syntax.

If you knew that to be true, why did you try to do the same thing yourself and say it was legal?

@Cubbi
Yes, I'm aware almost every example I evaluated in this thread is undefined, it doesn't mean there can't be a general consensus on how it should behave when it's physically encountered. I was just putting some common sense/logic behind the mysterious undefined behavior. I also enjoyed thinking about how each variable would interact in a (possible) defined case (there might be one some day, you never know).
Last edited on
If you knew that to be true, why did you try to do the same thing yourself and say it was legal?


I had in mind a = b, c, d ; which I'd considered you actually might've had in mind for int a = (b, c, d); because it made no sense.
That's why I said the comma in this situation is an operator and not a separator. It operates the declaration of variables
It's not an operator. An operator is something that does something with expressions and forms expressions. An expression is something that has a value and can be assigned to a variable. If the declaration comma is an operator, then what's the value of a declaration?

Likewise for the parameter separator.
cire wrote:
because it made no sense.

The OP was specifically about that situation, that's why I approached it. But I just wanted to make sure you were on the same page here.

helios wrote:
It's not an operator. An operator is something that does something with expressions and forms expressions. An expression is something that has a value and can be assigned to a variable. If the declaration comma is an operator, then what's the value of a declaration?

Likewise for the parameter separator.

This requires a little bit of an abstract thought process. Some Most will argue, but here is my view point. In the declaration example, I feel that the , is an operator for two reasons: One, it separates, then evaluates; Two, there is an expression and it can be assigned, but I don't believe it's required that during assignment it has to be to a variable.

The expression in int a = b, c, d; is (a = b), (c), (d). Now, here is where the abstraction comes from. All of those can be assigned, they're considered rvalues. The assignment comes in the place of the data type, in this case, int. So, the comma operator separates then evaluates each section, then assigns it to the declaration of an int. So we get:
1
2
3
int (a = b);
int (c);
int (d);


Does that not conform with the standard? What argument do you have against that logic (besides it just isn't an operator)?

As for the parameter separator, that's all the comma is in that situation, unless it's within another set of parenthesis. Same goes for the value initialization of arrays, objects, etc. It doesn't do anything per se, but it does serve a purpose in the language. That's why I originally stated that aside from parameter separation and initialization separation, the comma is always going to be an operator, however, not everyone sees it's application as so, that is my conclusion of it.

I don't believe my right, there is no wrong in my thought process, etc. I like to be proven wrong, but I like facts and not just "no it's not" answer. I'm wrong a lot, a lot more than I like, but putting my logic together, piece by piece, it makes perfect sense to me. Please, prove me wrong or make me understand why you think I'm wrong.

I can only imagine how much I look like a fool right now, and I wouldn't be surprised, however, I do like sharing my view points on debate topics.
it separates, then evaluates
The semicolon does that too. Does that make it an operator?

The expression in int a = b, c, d; is (a = b), (c), (d).
The C grammar implies that any expression surrounded by parentheses is also an expression. If what you're saying is true, then these three
1
2
3
int a = b, c, d;
int (a = b, c, d);
int (a = b), (c), (d);
are all legal and should have the same meaning.
They don't.

The expression in int a = b, c, d; is (a = b), (c), (d). Now, here is where the abstraction comes from. All of those can be assigned, they're considered rvalues. The assignment comes in the place of the data type, in this case, int. So, the comma operator separates then evaluates each section, then assigns it to the declaration of an int.

What argument do you have against that logic (besides it just isn't an operator)?
You're trying to make the case that P is true while using P in the argumentation. That's fallacious.
From 5.18:
5.18.2
In contexts where comma is given a special meaning, [ Example: in lists of arguments to functions (5.2.2) and lists of initializers (8.5) —end example ] the comma operator as described in Clause 5 can appear only in parentheses.[ Example:
f(a, (t=3, t+2), c);
has three arguments, the second of which has the value 5. —end example ]


Pretty clear. The comma operator is not used in the context you're asserting it is. And, while you might think it's harmless to think that way, code that depends on it being an operator can fail.

For instance, given the properties of the comma operator you might think that:
int a = b++, c = b++, d=b++;
was well defined, but it's not.

For instance, given the properties of the comma operator you might think that:
int a = b++, c = b++, d=b++;
was well defined, but it's not.
Can you find a source on this?
Can you find a source on this?


I'm not sure what you mean. The quoted portion clearly rules out the comma operator behavior here, so evaluations of the init-declarators are unsequenced, and thus the behavior is undefined as b is being modified more than once per 1.9.15, just the same as func(b++, b++, b++) would be.

Nothing in the declarators section suggests there is anything special about the sequencing of init-declarator evaluation. Interestingly enough, the standard does provide that each initializer-clause of a an initializer-list of a braced-init-list is sequenced before the next clause.

[Edit: spelling]
Last edited on
cire wrote:
so evaluations of the init-declarators are unsequenced,

actually, comma-separated initializers are sequenced, see 8[dcl.decl]/3

(but yes, they have nothing whatsoever to do with operator comma)

see also: http://stackoverflow.com/questions/6414030/is-the-comma-in-a-variable-list-a-sequence-point
The quoted portion clearly rules out the comma operator behavior here, so evaluations of the init-declarators are unsequenced, and thus the behavior is undefined as b is being modified more than once per 1.9.15, just the same as func(b++, b++, b++) would be.
I don't think it's the same, though. The function call creates a larger expression; the declaration doesn't. Thus, there should be a sequence point after each expression. The only real question is in which order the initialization occurs.
AFAIK, this is well defined. The expression that appears in an initializer is a full-expression.

1
2
int b = 10 ;
int a = b++, c = b++, d = b++ ; 


A full-expression is an expression that is not a subexpression of another expression.
...
Every value computation and side effect associated with a full-expression is sequenced before every value
computation and side effect associated with the next full-expression to be evaluated.


Duplicate post; didn't see the posts by Cubbi and helios when I made it.
Last edited on
Each init-declarator in a declaration is analyzed separately as if it was in a declaration by itself.


Ergh. What does "analyzed" mean in this statement?

I assumed it had to do with how it was analyzed when parsed (indeed, analyze doesn't seem to have any special meaning in the standard and the only other places variations of it appear are in relation to parsing or tokenizing.) Having taken a closer look at the note, though, I can see where you're coming from, even though notes aren't normative. I wish the language was clearer.

I certainly can't trick my compilers into mixing up the order of evaluation. =)



cire wrote:
5.18.2
In contexts where comma is given a special meaning, [ Example: in lists of arguments to functions (5.2.2) and lists of initializers (8.5) —end example ] the comma operator as described in Clause 5 can appear only in parentheses.[ Example:
f(a, (t=3, t+2), c);
has three arguments, the second of which has the value 5. —end example ]


The standard is wrong, it has no clue what it's talking about. I can't be wrong, I'm never wrong.

Just kidding

But in all seriousness, I thought I had something going, but the more and more I thought about it, especially tonight at work, I started to realize too many issues that I obviously overlooked. I can't physically argue with the standard saying that the comma operator can only be used when it's surrounded by parenthesis.

@Everyone in this thread at the moment
Do you all just have copies of the standard laying around? I know bits and pieces of it float around on the internet, but that's a very large document, if I'm not mistaken. I also know it's not free, but that's the easy part. The reason I ask is because a lot of you talk about it like you use it as night time reading material, or while you're going to the bathroom, sitting in traffic, pick your spare time event.

Although the standard specifies a lot, is it worth just having? I doubt I'd read it all, maybe at best use it as reference if I use it at all. I find it hard to completely understand all of the jargon used specifications of software, let alone specifications used to create said software in the first place.

I've joined a Usenet group on Google, but even reading some of the posts there, most of what they talk about is way above my league, and after reading so much, I completely forget everything I read (sensory overload).

I know this stuff doesn't just come over night, but most of you who debated me obviously have more experience/knowledge in this field. My knowledge is still limited, and if I have a specific thing to look up, I'll do it on my own. I don't typically browse forums, aside from here, looking for new things to learn, nor do I scan google and websites just for basic information, but I do get a hair up my butt once in a while and wiki something I think I know, used to know, or have been curious about.

Any specific recommendations?
Last edited on
> Although the standard specifies a lot, is it worth just having?

Every professional C++ programming house would have a (shared) copy of the IS. It is not intended to be learning material; it is primarily used for reference. The ARM, even if it dated, is still a very good resource to learn the basics - issues like the ones discussed in this thread.

IMHO, it is not worth buying an official copy of the IS for personal use; that money would be better spent in the purchase of a good book that you do not possess.

It would be good to have a draft of the IS lying around. Though the FDIS is not available, the working draft n3337 is close enough for all practical purposes.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf
Pages: 123