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-seqor 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