Some refactoring led to a piece of code that led me to this minimal testcase:
int main () {
if (int i=1) {
/* IF-BLOCK */
} else {
throw i;
}
}
This compiles fine. However, I always assumed that i
is only visible to IF-BLOCK
, but it seems that it's not. Is this a compiler bug?
Also, why does the following work?
int main () {
if (int i=1) {
} else if (int i=2) {
} else {
throw i;
}
}
Note the second if
"re-declares" i
. Another compiler bug?
Scope is the context in which a variable, procedure, class, or type is declared. Scope affects the accessibility of an item's value outside that context. For example, variables declared within a procedure are typically not available outside of the scope of that procedure.
If you're new to the syntax that's used in the code sample, if (int i = 5) { is a perfectly valid way of declaring and defining a variable, then using it inside the given if statement. It allows us to write terser, clearer code, while also avoiding limiting the scope of a variable.
if is a conditional statement, which returns true or false based on the condition that is passed in it's expression. By default, if-statement is implemented on only one line, that follows it. But if we put block after the if-statement, it will be implemented on the whole block.
No, this is actually correct behavior.
6.4 Selection statements [stmt.select]
A name introduced by a declaration in a condition (either introduced by the
type-specifier-seq
or the declarator of the condition) is in scope from its point of declaration until the end of the substatements controlled by the condition. If the name is re-declared in the outermost block of a substatement controlled by the condition, the declaration that re-declares the name is ill-formed. [ Example:if (int x = f()) { int x; // ill-formed, redeclaration of x } else { int x; // ill-formed, redeclaration of x }
— end example ]
(Emphasis mine)
This basically means that the scope of i
begins in the condition, and ends after the if
-block, where the else
-block is part of the if
-block, too.
Your second problem with the nested if
is based on the (wrong) assumption that an else-if
is part of the introductory if
, but it really isn't. The if (int i=2)
is the body of the first else
!
if (int i=1)
|
/ \
/ \
/ \
/ \
/ \
if-block else
|
if(int i=2)
/ \
/ \
/ \
if-block throw i
What this means in turn:
int main () {
if (int i=1) {
} else if (1) {
throw (i+2);
} else {
throw i;
}
}
This code is valid, as the i
-declaration is visible in throw (i+2);
, but it is still valid to hide the first i
, because in nested scopes, names can be overriden:
int main () {
if (int i=1) {
} else if (int i=2) {
throw (i+2); // now refers to `int i=2`
} else {
throw i;
}
}
So all in all, don't panic: Writing tokenizers or parsers or something using the pattern found in the last statement still works, the relevant new knowledge here is that any declaration in a condition spans the whole if
-tree, but can be overriden in any nested if
.
Also, be assured that the following is still invalid (even though it was valid in old compilers):
if (int i=0) {}
std::cout << i; // nope, not valid
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With