Is there a way to declare, assign and compare a variable to an expression in an if construction in such a way that it is only defined in the scope of the if construction?
This works (declare and assign, but of course the condition is only the return value of function f being equal to zero or not):
int main()
{
if(int i = f())
{
printf("%d", i);
// i is defined here!
}
else
{
// Here too!
}
// But not here!
}
But when I try to compare the value of i with an actual expression I run into trouble:
int main()
{
// Does not compile because "int i = f()" is not a primary expression?
if((int i = f()) == 3)
{
printf("%d", i);
}
}
Creating a scope around the whole if construction kind of does the trick, from a behavior point of view, but it looks ugly in my opinion:
int main()
{
{
int i = f();
if(i == 3)
{
printf("%d", i);
// i is defined here!
}
// here too!
}
// i is not defined here!
}
I'm comparing with the look and feel of for-loops and switches where it's so neat to declare and assign a variable so it is only defined in the scope in question. Of course the value of the variable is not compared to anything there and i'm not saying it's the same thing:
for(int i = 0;;)
{
break;
}
// i is not defined here
switch(int i = f())
{
default: break;
}
// i is not defined here!
So to sum it up, is there a way to tie the definition of a variable to the scope of "if" in a similar way as it's commonly tied to the scope of for and (perhaps not as commonly) switch, and where you actually compare the value of the variable to an expression as the condition of the if-statement?
As far as I can tell there is no way to have both a declaration and an expression within the condition of an if statement. If we look at the draft C++ standard section 6.4
Selection statements the grammar for if is as follows:
selection-statement:
if ( condition ) statement
if ( condition ) statement else statement
switch ( condition ) statement
condition:
expression
attribute-specifier-seqopt decl-specifier-seq declarator = initializer-clause
attribute-specifier-seqopt decl-specifier-seq declarator braced-init-list
So you either can use an expression or a declaration and I don't see any obvious ways around that.
What you proposed in the alternative, declaring i
before the if statement seems like the best option. Although using an enclosing block does not seem necessary:
int i = f();
if(i == 3)
You can declare the variable in the if
, but if you do so, the
condition depends on the implicit conversion of the type to
bool
, which is very limiting and a bit obfuscating. The
definition in the for
works because the first part of the
for
isn't part of the condition. Just write:
int i = f();
if ( i == 3 ) {
// ...
} else {
// ...
}
This leaves the variable in scope until the end of the enclosing
block, but the enclosing block can't be bigger than the entire
function; if leaving it in scope is a problem, then your
functions are too large and complex, and need to be refactored.
You can only do a declaration OR boolean logic in an if
statement. The C++ spec says so somewhere, forgot where exactly. Therefore a code like:
if (int x = 3 && x == 3) {}
will never compile because it will also throw the error that x
is used uninitialized
The first snippet works because you are declaring and defining i
in if
's conditional expression. It will always evaluated to true
.
The second snippet does not compile because you are comparing a non-primary (because i
is declared and defined here) expression in conditional expression with a primary expression.