Reading http://en.cppreference.com/w/cpp/language/for I find, that condition part of for loop can be either expression, contextually convertible to bool, or single-variable-declaration with mandatory brace-or-equal initializer (syntax specification in 6.4/1):
condition:
expression
type-specifier-seq declarator = assignment-expression
But I have never seen a using of the later in a source code.
What is the profitable (in sense of brevity, expressiveness, readability) making use of variable declaration in condition part of for loop statement ?
for (int i = 0; bool b = i < 5; ++i) {
// `b` is always convertible to `true` until the end of its scope
} // scope of `i` and `b` ends here
Variable declared in condition can be only convertible to true during whole period of lifetime (scope) if there no side effects influencing on result of convertion to bool.
I can imagine only a couple of use cases:
declaration a variable of class type, having user-defined operator bool.
some kind of changing cv-ref-qualifiers of loop variable:
for (int i = 5; int const & j = i; --i) {
// using of j
}
But both of them are very artifical.
All three statements if, for and while can be used in a similar way. Why is this useful? Sometimes it just is. Consider this:
Record * GetNextRecord(); // returns null when no more records
Record * GetNextRecordEx(int *); // as above, but also store signal number
// Process one
if (Record * r = GetNextRecord()) { process(*r); }
// Process all
while (Record * r = GetNextRecord()) { process(*r); }
// Process all and also keep some loop-local state
for (int n; Record * r = GetNextRecordEx(&n); )
{
process(*r);
notify(n);
}
These statements keep all the variables they need at the minimal possible scope. If the declaration form wasn't allowed inside the statement, you would need to declare a variable outside the statement but you would only need it for the duration of the statement. That means you would either leak into too large a scope, or you would need unsightly extra scopes. Allowing the declaration inside the statement offers a convenient syntax, which although rarely useful is very nice to have when it is useful.
Perhaps the most common-place use case is in a multiple-dispatch cast situation like this:
if (Der1 * p = dynamic_cast<Der1 *>(target)) visit(*p);
else if (Der2 * p = dynamic_cast<Der2 *>(target)) visit(*p);
else if (Der3 * p = dynamic_cast<Der3 *>(target)) visit(*p);
else throw BadDispatch();
As an aside: only the if statement admits a code path for the case where the condition is false, given in an optional else block. Neither while nor for allow you to consume the result of the boolean check in this way, i.e. there is no for ... else or while ... else construction in the language.
Related
The following code containing a while loop compiles in C++.
#include <iostream>
using namespace std;
int main() {
while (int i = 5)
{
break;
}
return 0;
}
However, the following equivalent C code results in an error if compiled in C:
#include <stdio.h>
int main() {
while (int i = 5)
{
break;
}
return 0;
}
Compiler output:
> prog.c: In function 'main': prog.c:5:9: error: expected expression
> before 'int' while (int i = 5)prog.c: In function 'main':
> prog.c:5:9: error: expected expression before 'int' while (int i =
> 5)
Why does this happen? I tried to look up the documentation for the while loop in C, but haven't been able to locate that either.
C and C++ are different languages. <iostream> is not part of C library, and using and namespace are C++ keywords only. Don't mix the languages, as they are not at all the same.
Also, as #sasquatch mentioned, it is illegal in C to declare a variable in the while condition.
You should not expect C++ code to compile in C. You should also not expect the other way around, since C is not a proper subset of C++.
In C++, a condition is tested for before each iteration of a while loop. Verbatim from the C++ reference:
condition - any expression which is contextually convertible to
bool or a declaration of a single variable with a brace-or-equals
initializer. This expression is evaluated before each iteration, and
if it yields false, the loop is exited. If this is a declaration, the
initializer is evaluated before each iteration, and if the value of
the declared variable converts to false, the loop is exited.
Whereas in C, an expression is tested for before each iteration of a while loop. Verbatim from the C reference:
expression - any expression of scalar type. This expression is
evaluated before each iteration, and if it compares equal to zero,
the loop is exited.
In C, the while expects an expression inside the parenthesis. What you have is a declaration of the variable. You would have to declare the variable before the loop and then write the expression as i == 5 to compile in C.
This post covers what C expects compared to C++ in more detail. The same rules that they explain for an if also applies to a while.
There is a difference in the definition of the while statement in C++ and C.
In C++ the while statement is defined the following way
while ( condition ) statement
where in turn the condition is defined like
condition:
expression
attribute-specifier-seqopt decl-specifier-seq declarator = initializer-clause
attribute-specifier-seqopt decl-specifier-seq declarator braced-init-list
As you can see apart from an expression the condition may be a declaration with some initializer. The value of ibitializer is converted to an expression of type bool and the while statement is executed depending on the boolean value.
So in your C++ program the value of the initializer of the declaration in the condition of the while statement is equal to 5
while (int i = 5)
As it is not equal to zero then it is converted to boolean true.
In C the while statement is defined the following way
while ( expression ) statement
As you can see yourself here is explicitly specified that only expressions may be used. C does not allow to use declarations in the while statement. So this statement
while (int i = 5)
will not be compiled in C.
It is not the only difference between C++ and C. For example this conditional operator below will be compiled in C++ and will not be compiled in C
int x = 10;
int y = 20;
( x < y ? x : y ) = 20;
Or this statement will be compiled in C++ and will not be compiled in C
int x;
int y = 20;
++( x = y );
The code snippet below will yield different results in C++ and C
if ( sizeof( 'A' ) == 1 ) puts( "They are equal" );
else puts( 'They are not equal" );
Or consider the following example
int x = 10;
void *vp = &x;
int *ip;
ip = vp;
This code snippet will be compiled in C and will not be compiled in C++. So you should be caution.
Moreover C and C++ have even different fundamental types. For example in C there is integer type _Bool that is absent in C++. On the other in C++ there is type bool and corresponding boolean literals false and true that is absent in C. In C++ there is pointer literal nullptr that is absent in C. Or in C there are compound literals that are absent in C++. Or in C++ there is the range based for statement that is absent in C and so on.:)
There are multiple issues with the code you have above.
First off you may want to get rid of both the name space and the header. They are not even being used in the code and are not able to be read by the c compiler either.
Second, you cannot define variable types in any looping commands. For example while (int i != 5) and for (int i =0 ...) is invalid in c. You have to define the variable before the loop.
Finally, although I believe the c++ standard allows you to define a variable in a while statement, I highly suggest not doing so. Its semi confusing to have a comparison statement mixed with a variable definition ie: int x, bool y, double z, etc. etc.
I stumbled recently in this problem
for(int i=0,n=v.size(); i<n; i++) {
...
P2d n = ... <<<--- error here
}
the compiler was complaining about the fact that the n local variable has been already defined, despite that the open brace looks like it should start a new scope.
Indeed the standard has a special wording for this and while the code compiled fine with g++4.6.3, it complains with more recent versions and other compilers.
What is the rationale (if there is any) behind this special rule?
To be more clear: the standard explains that this is not permitted and I've no questions about the technical reason for which that's an error: I was just wondering why the committee decided to use special extra rules instead of just creating another nested scope when seeing the opening brace (like it happens in other places).
For example to make the code legal you can just wrap the body with two brace pairs instead of one...
Please also note that braces after for/while/if, while considered good practice, are not mandatory and not part of the syntax, but still a scope containing the loop variables exists (therefore using function definition as another example where the scope of the locals is the body of the function is not relevant: a function body is not a statement and braces are mandatory).
In the C++ syntax the body of a for is just a statement; however if this statement happens to be a braced group then it gets a special handling in for/while/if (that doesn't happen when you use a braced group as statement elsewhere in the language).
What is the reason for adding this extra complication to the language? It's apparently not needed and just treating the braces as another inner scope seems (to me) simpler.
Are there use cases in which this simpler and more regular approach doesn't work?
Note that I'm not asking opinions. Either you know why the committee took this decision (requiring also a quite elaborate wording in the standard instead of just having the body as a regular statement with the regular handling of a brace enclosed block when used as statement) or you don't.
EDIT
The "single scope" view for the syntax is for me unnatural but technically possible for the for statement that can be rationalized as a single block with a backward goto statement, but it's hard to defend in a very similar case for the if statement:
if (int x = whatever()) {
int x = 3; // Illegal
} else {
int x = 4; // Illegal here too
}
but this is instead legal
if (int x = whatever()) {
int z = foo();
} else {
int z = bar();
}
So are the condition, the then part and the else part of an if statement the same scope? No because you can declare two z variables. Are they separate scopes? No because you cannot declare x.
The only rationalization I can see is that the then and else part are indeed separate scopes, but with the added (strange) rule that the variable declared in the condition cannot be declared in the scope. Why this extra strange limitation rule is present is what I'm asking about.
int i = 0;
for (MyObject o1; i<10; i++) {
MyObject o2;
}
Can be translated from the point view of recent compilers into:
int i = 0;
{
MyObject o1;
Label0:
MyObject o2; //o2 will be destroyed and reconstructed 10 times, while being with the same scope as o1
i++;
if (i < 10)
goto Label0;
}
This is the answer to your last question mark at the end, they didn't add something complicated, just used goto to label in the same scope, and not goto to out of the scope and then enter to it again. I don't see clear reason why it's better. (While it will do some incompatibility with older codes)
The semantics are not special for the for loop! if (bool b = foo()) { } works the same. The odd one out is really a { } block on its own. That would be rather useless if it didn't introduce a new scope. So the apparent inconsistency is due to a misplaced generalization from an exceptional case.
[edit]
An alternative view would be to consider an hypothetical, optional keyword:
// Not a _conditional_ statement theoretically, but grammatically identical
always()
{
Foo();
}
This unifies the rules, and you wouldn't expect three scope (inside, intermediate,outside) here either.
[edit 2] (please don't make this a moving target to answer)
You wonder about lifetime and scopes (two different things) in
int i = 0;
for (MyObject o1; i<10; i++) {
MyObject o2;
}
Let's generalize that:
MyObject o2; // Outer scope
int i = 0;
for (MyObject o1; i<o1.fooCount(); i++) {
std::cout << o2.asString();
MyObject o2;
}
Clearly the call to o2.asString() refers to the outer o2, in all iterations. It's not like the inner o2 survives the loop iteration. Name lookup doesn't will use names from the outer scope when the names aren't yet defined in the inner scope - and "not yet defined" is a compile-time thing. The repeated construction and destruction of the inner o2 is a runtime thing.
Look at it this way:
A pair of braces allows you to hide variables visible inside an enclosing pair of braces (or globally):
void foo(int n)
{
// the containing block
for (int i = 0; i < n; ++i)
{
int n = 5; // allowed: n is visible inside the containing { }
int i = 5; // not allowed: i is NOT visible inside the containing { }
}
}
If you think about it this way you realize there are no special rules here.
The brackets ({}) deliminate a section of code as a block. Everything in this block is within it's own local scope:
int main(int argc, char** argv)
{
int a = 5;
std::cout<<a<<std::endl // 5
{
int a = 10;
std::cout<<a<<std::endl //10
}
std::cout<<a<<std::endl // 5
}
But wait, there is something else in that code...
int main(int argc, char** argv)
{
}
This is similar to the structure of a for loop:
for (int i = 0 ; i < 5; i++)
{
}
The function definition has code outside the {...} block too!
in this case, argc and argv are defined, and they are local to the scope of the function just like the definition of i in the above for loop.
In fact you can generalise the syntax to:
definition { expression }
Where the entirety of the above is within the scope.
In this case, the 'raw' brackets ({}) form the same structure but with an empty definition statement.
edit:
to answer your edit, in:
int i = 0;
for (MyObject o1; i<10; i++) {
MyObject o2;
}
the constructor for o2 is looped over for each loop, while the the constructor for o1 isn't.
for loop behavior goes as follows (where XXX is the current block being executed:
init
for(XXX; ; ){ }
test loop exp
for( ;XXX; ){ }
execute block
for( ; ; ){XXX}
final operation
for( ; ;XXX){ }
Back to 2.
As there is there was the c tag I would answer from that perspective. Here is an example:
#include <stdio.h>
int main(void) {
int a[] = {1, 2, 3, 4, 5, 6, 7, 8};
for (int i = 0, n = 8; i < n; i++) {
int n = 100;
printf("%d %d\n", n, a[i]);
}
return 0;
}
It compiles without issues, see it working at ideone (C99 strict mode, 4.8.1).
C standard is clear that both scopes are considered as separate, N1570 6.8.5/p5 (emphasis mine):
An iteration statement is a block whose scope is a strict subset of
the scope of its enclosing block. The loop body is also a block whose
scope is a strict subset of the scope of the iteration statement.
There is a warning, but only with the -Wshadow option, as expected:
$ gcc -std=c99 -pedantic -Wall -Wextra -Wshadow check.c
check.c: In function ‘main’:
check.c:7: warning: declaration of ‘n’ shadows a previous local
check.c:6: warning: shadowed declaration is here
The loop control variables (i and n in this case) are considered part of the for loop.
And since they are already declared in the loop's initialization statement, most attempts (other than re-defining by using nested braces) to re-define them within the loop results in an error!
I cannot tell you why there is just one scope opened by the for loop, not a second one due to the braces. But I can say what was given back then as the reason for changing where that single scope is: Locality. Take this kind of pretty standard code:
void foo(int n) {
int s=0;
for (int i=0; i<n; ++i) {
s += global[i];
}
// ... more code ...
for (int i=0; i<n; ++i) {
global[i]--;
}
}
Under the old rules, that would have been illegal code, defining i twice in the same scope, the function. (In C back then, it was even illegal because you had to declare variables at the beginning of the block.)
That usually meant you’d leave out the declaration in the second loop – and run into problems if the code with the first loop was removed. And whatever you did, you had variables with a long time to live, which as usual makes reasoning about your code harder. (That was before everyone and their brother started to consider ten lines a long function.) Changing for to start its own scope before the variable declaration here made code much easier to maintain.
You problem is that the definition part of the for is considered inside the scope of the for.
// V one definition
for(int i=0,n=v.size(); i<n; i++) {
...
// V second definition
P2d n = ... <<<--- error here
}
Out of curiosity I started wondering if it's possible to have a ternary expression that, if it evaluates to false, does nothing in the false branch.
Ie is there a way to write something like this:
variable = (someBool) ? i : <do nothing>;
As opposed to:
if (someBool) {
variable = i;
}
I tried ((void)0) or while(false){}; as no-op but the compiler expects an expression.
UPDATE:
I realized the question lost some meaning because I tried to make the code easier. The initial idea I had was to initialize a static var with a ternary - using the static var itself as the condition:
static int var = (var != 0) ? var = 1 : (var already initialized, do nothing);
This is assuming that uninitialized variables are initialized to 0 which is not always true (or never in release builds, not quite sure). So maybe it's a hypothetical question.
how about short-circuit?
int variable = 0;
bool cond = true; // or false
(cond && (variable = 42));
printf("%d\n", variable);
How about this:
variable = (someBool) ? i : variable ;
Though I would personally prefer the original if statement
Compilers not only expect expression, but the expression the returns type on the left side (the type of variable whatever is it). So, no you can not do that. It's not conditional execution, but variable member assignment.
These are completely different things.
In second example :
if (someBool) {
variable = i;
}
you do not assign anything, but simply execute based on condition. So in your case, where you don't want to do anything (not assign anything), the way to go is conditional execution so use simply the second case.
The format of the conditional expression is
<expression> ? <expression> : <expression>
In other words, it must have some expression.
Addressing your edit: in C99 variables of static scope are initialised to 0. However, I have never really trusted that because I've been programming in C since the K&R days.
Anyway, just initialise the variable. As the variable is static, it's only going to happen once during the whole execution time of the program.
You could do:
variable = !someBool ?: i;
Since the ?: will no-op when the if expression is true but assign i if it's false.
Note: This has only been tested in Obj-C
How about
(someBool) ? (variable = i) : NULL;
For C# says:
Syntax:
condition ? first_expression : second_expression;
And it says about first_expression and second_expression:
Either the type of first_expression and second_expression must be the same, or an implicit conversion must exist from one type to the other.
If you were to evaluate a nullable object type instead of bool, you could always write:
variable = myVar ?? i;
Hacky/cludgey/impractical - probably all 3, but for the sake of this question it's a way of omitting an 'else'.
Try: null lambda.
auto null_lambda = [](){return;};
int a = 1;
int b = 2;
vector<int> c;
a > c ? b = c.push_back(b) : null_lambda();
I tried the following:
if(int i=6+4==10)
cout << "works!" << i;
if(int i=6+4,i==10)
cout << "doesn't even compile" << i;
The first works fine while the second doesn't compile. Why is this?
EDIT: Now I know that the first one may not work as I intend it to. The value of i inside the if scope will be 1, not 10. (as pointed out by one of the comments on this question).
So is there a way to initialize and use a variable inside of an if statement at the same time similar to for(int i=0;i<10;i++)? So that you could produce something like if((int i=6+4)==10) (which will not compile) where the value of I inside the if scope would be 10?
I know you could declare and initialize I before the if statement but is there a way to do this within the statement itself?
To give you an idea why I think this would be usefull.
if(int v1=someObject1.getValue(), int v2=someObject2.getValue(), v1!=v2)
{
//v1 and v2 are visible in this scope
//and can be used for further calculation without the need to call
//someObject1.getValue() und someObject2.getValue() again.
}
//if v1==v2 there is nothing to be done which is why v1 und v2
//only need to be visible in the scope of the if.
The expression used as an initializer expression must be an assignment-expression so if you want to use a comma operator you must parenthesize the initializer.
E.g. (not that what you are attempting makes much sense as 6 + 4 has no side effects and the value is discarded and i == 10 uses the uninitialized value of i in its own initializer.)
if (int i = (6 + 4, i == 10)) // behaviour is undefined
Did you really mean something like this?
int i = 6 + 4;
if (i == 10)
When using the form of if that declares a new variable the condition checked is always the value of the initialized variable converted to bool. If you want the condition to be an expression involving the new variable you must declare the variable before the if statement and use the expression that you want to test as the condition.
E.g.
int i;
if ((i = 6 + 4) == 10)
I doubt seriously either example works to do anything useful. All that it does is evaluate to "true" in a complicated fashions.
But the reason the second one doesn't compile is that it's interpreted as two declarations: int i = 6+4; int i==10 and int i==10 isn't valid because that's an equality operator, not an assignment.
There are different alternatives, because what you want cannot be done (you cannot mix the comma operator with declarations). You could, for example, declare the variable outside of the if condition:
int i = 6+4;
if ( i == 10 ) ...
Or you can change the value of i to be 0 instead of 10 and recalculate i inside the else block:
if ( int i = (6+4)-10 ) ; else {
i += 10;
// ...
}
Much simpler, don't declare the variable at all, since you know the value inside the loop:
if ( (6+4)==10 ) {
int i = 10;
// ...
}
Unless of course you need the value of i in the case where it is not 10, in which case the second option is the most appropriate.
As of C++17 what you were trying to do is finally possible:
if (int i=6+4; i==10)
cout << "works, and i is " << i << endl;
Note the use of ; of instead of , to separate the declaration and the actual condition.
or, "Declaring multiple variables in a for loop ist verboten" ?!
My original code was
for( int i = 1, int i2 = 1;
i2 < mid;
i++, i2 = i * i ) {
I wanted to loop through the first so-many squares, and wanted both the number and its square, and the stop condition depended on the square. This code seems to be the cleanest expression of intent, but it's invalid. I can think of a dozen ways to work around this, so I'm not looking for the best alternative, but for a deeper understanding of why this is invalid. A bit of language lawyering, if you will.
I'm old enough to remember when you had to declare all your variables at the start of the function, so I appreciate
the
for( int i = 0; ....
syntax. Reading around it looks like you can only have one type declaration in the first section of a for() statement. So you can do
for( int i=0, j=0; ...
or even the slightly baroque
for( int i=0, *j=&i; ...
but not the to-me-sensible
for( int i=0, double x=0.0; ...
Does anyone know why? Is this a limitation of for()? Or a restriction on comma lists, like "the first element of a comma list may declare a type, but not the other? Are the following uses of commas distinct syntactical elements of C++?
(A)
for( int i=0, j=0; ...
(B)
int i = 0, j = 0;
(C)
int z;
z = 1, 3, 4;
Any gurus out there?
====================================================
Based on the good responses I've gotten, I think I can sharpen the question:
In a for statement
for( X; Y; Z;) {..... }
what are X, Y and Z?
My question was about C++, but I don't have a great C++ refrence. In my C reference (Harbison and Steele 4th ed, 1995), they are all three expressions, and my gcc requires C99 mode to use for( int i = 0;
In Stroustrup, sec 6.3, the for statement syntax is given as
for( for-init-statement; condition; expression ) statements
So C++ has a special syntactic statement dedicated to the first clause in for(), and we can assume they have special rules beyond those for an expression. Does this sound valid?
If you need to use several variables of different type in for-loop then you could use structures as follows:
for( struct {int i; long i2;} x = {1, 1}; x.i2 < mid; x.i++, x.i2 = x.i * x.i )
{
cout << x.i2 << endl;
}
so this is not a limitation, just use a little different syntax.
int i = 1, double i2 = 0; is not a valid declaration statement, so it cannot be used inside the for statement. If the statement can't stand alone outside the for, then it can't be used inside the for statement.
Edit:
Regarding your questions about comma operators, options 'A' and 'B' are identical and are both valid. Option 'C' is also valid, but will probably not do what you would expect. z will be assigned 1, and the statements 3 and 4 don't actually do anything (your compiler will probably warn you about "statements with no effect" and optimize them away).
Update:
To address the questions in your edit, here is how the C++ spec (Sec 6.5) defines for:
for ( for-init-statement condition(opt) ; expression(opt) ) statement
It further defines for-init-statement as either expression-statement or simple-declaration. Both condition and expression are optional.
The for-init-statement can be anything that is a valid expression-statement (such as i = 0;) or simple-declaration (such as int i = 0;). The statement int i = 1, double i2 = 0; is not a valid simple-declaration according to the spec, so it is not valid to use with for. For reference, a simple-declaration is defined (in Section 7) as:
attribute-specifier(opt) decl-specifier-seq(opt) init-declarator-list(opt) ;
where decl-specifier-seq would be the data type plus keywords like static or extern and init-declarator-list would be a comma-separated list of declarators and their optional initializers. Attempting to put more than one data type in the same simple-declaration essentially places a decl-specifier-seq where the compiler expects a init-declarator-list. Seeing this element out of place causes the compiler to treat the line as ill-formed.
The spec also notes that the for loop is equivalent to:
{
for-init-statement
while ( condition ) {
statement
expression ;
}
}
where condition defaults to "true" if it is omitted. Thinking about this "expanded" form may be helpful in determining whether a given syntax may be used with a for loop.
It's actually a limitation of declaration statements:
int i=0, j=0, *k=&i; // legal
int i=0, double x=0.0; // illegel
So, basically, the answer to your final question is: (A) & (B) are the same. (C) is different.
As bta points out:
z = 1,3,4;
is the same as
z = 1;
However, that is because = has a higher precedence than ,. If it were written as:
z = (1,3,4);
then that would be the same as:
z = 4;
As long as you can write a valid statement with the comma , operator, it's acceptable.
C++ (also C and Java) do not permit the declaration of more than one type of variables in the scope of a for loop. In the grammar, that is because the comma does not start a new statement in that context. Effectively, only one declaration is allowed inside the for(;;) statement. The rationale is because that requirement is fairly unusual, and you can get it only with a slightly more verbose construct.
Well, I did some more googling, and I think the answer for C++ is "for() statements are very special places" Ick.
Excerpting from an ISO spec:
for ( for-init-statement conditionopt ; expressionopt ) statement
where
for-init-statement:
expression-statement
simple-declaration
and they have to specify that
[Note: a for-init-statement ends with a semicolon. ]
So the C++ syntax spec. is specifically hacked so that only one decl-spec (i.e. type) is allowed in the first slot. Looks like our attempts to argue from basic principles were doomed. Thanks for all the responses.
I can see why you hope that would work, but---given that even using the rather simple minded teaching tool that
for (i=0; i<max; i++){
...
}
is equivalent to
i=0;
while (i<max){
...
i++;
}
you syntax doesn't work---I can't see why you expected that it would. EAch of the bits need to be valid.