tags:

views:

626

answers:

6

You can, obviously, put a variable declaration in a for loop:

for (int i = 0; ...

and I've noticed that you can do the same thing in if and switch statements as well:

if ((int i = f()) != 0) ...

switch (int ch = stream.get()) ...

But when I try to do the same thing in a while loop:

while ((int ch = stream.get()) != -1) ...

The compiler (VC++ 9.0) does not like it at all.

Is this compliant behavior? Is there a reason for it?

EDIT: I found I can do this:

while (int ch = stream.get() != -1) ...

but because of precedence rules, that's interpreted as:

while (int ch = (stream.get() != -1)) ...

which is not what I want.

+2  A: 

It might be because the contents of the while clause are evaluated each loop, thus it would try and declare "ch" multiple times.

The if, switch, and for loop examples you gave will all have "ch" being defined only once.

RB
+10  A: 

This doesn't appear to be compliant behaviour. Part 6.5.1.2 of the standard states:

When the condition of a while statement is a declaration, the scope of the variable that is declared extends from its point of declaration (3.3.1) to the end of the while statement. A while statement of the form

while (T t = x) statement

is equivalent to

label:
{ //start of condition scope
    T t = x;
    if (t) {
        statement
        goto label;
    }
}

So in your example, ch should be declared within the scope of the loop and work correctly (with it being recreated through each loop iteration). Reason for the observed behaviour is most likely due to the compiler not scoping the variable correctly and then declaring it multiple times.

workmad3
The compiler is perfectly compliant, it's impossible to do what the question asks about. See my answer below.
Arkadiy
+2  A: 

You can put a variable declaration in the test expression of a while loop. What you cannot do is put a declaration statement in other expressions. For instance, in the expression a+b+c, you cannot replace b by int i = f(). And the same hold for the expression (a); you can't insert int i=f() to get an expression (int i=f()).

So, in while (int i = foo()), the outermost brackets are part of the while statement, and not of the text-expression, and everything is legal. In while ((int i = foo())), the outermost brackets are still part of the while statement. The test-expression would have the form "(" expr ")", and you end up with a syntax error.

MSalters
A: 

Try This doesn't work

while (int ch = stream.get(), ch != -1) ...

I've never tried it, but if the comment in your edit is correct, this should work.
VS 2005 won't even compile it.

Mark Ransom
This code is interpreted by the compiler as: int ch = (stream.get(), ch != -1)
Richard Corden
According to my sources, the comma operator is at the bottom of the precedence scale - but there's something else broken with my construct.
Mark Ransom
+2  A: 

The grammar for a condition in the '03 standard is defined as follows:

condition:
  expression
  type-specifier-seq declarator = assignment-expression

The above will therefore only allow conditions such as:

if ( i && j && k ) {}
if ( (i = j) ==0 ) {}
if ( int i = j ) {}

The standard allows the condition to declare a variable, however, they have done so by adding a new grammar rule called 'condition' that can be an expression or a declarator with an initializer. The result is that just because you are in the condition of an if, for, while, or switch does not mean that you can declare a variable inside an expression.

Richard Corden
Right - the key is that a declaration is not an expression.
Michael Burr
+1  A: 

The problem is, the standard permits you a declaration inside parenthesis. What you want to do is to get a declaration as part of expression, which is something that standard will not let you do.

while() can have one of two syntaxes: while() or while(). The declaration uses "=", and looks like expression, but it's a different syntactical entity.

When you write

while(int i = 1) {
}

, that's perfectly fine. "int i=1" is a declaration. However, what you want is

while ( (int i = 1) + 3) {
}

This is a very different animal. You want an expression inside while(), where one of the terms of the expression is a declaration. Now, declaration is a statement, and as such cannot be part of expression. That's why what you need to be done cannot be done.

(after writing the whole rant, I noticed that 2 other people wrote the same thing. Oh well, the more the merrier. The accepted answer is still wrong at the time of my writing.)

Arkadiy