Search code examples
c++initializationdeclarationassignment-operator

Why is int x{ y = 5 } possible?


int main() {
    int y;
    int x{ y = 5 };
    //x is 5
}

How is this possible, since y = 5 is not a calculable expression?

Also, why doesn't the compiler or IDE complain about main() not returning an int?


Solution

  • I will start from your last question

    Also, why doesn't the compiler or IDE complain about main() not returning an int?

    According to the C++ Standard (6.6.1 main function)

    5 A return statement in main has the effect of leaving the main function (destroying any objects with automatic storage duration) and calling std::exit with the return value as the argument. If control flows off the end of the compound-statement of main, the effect is equivalent to a return with operand 0 (see also 18.3).

    And relative to this question

    How is this possible, since y = 5 is not a calculable expression?

    From the C++ Standard (8.18 Assignment and compound assignment operators)

    1 The assignment operator (=) and the compound assignment operators all group right-to-left. All require a modifiable lvalue as their left operand and return an lvalue referring to the left operand.

    Sp this declaration

    int x{ y = 5 };
    

    can be equivalently split into two statements

    y = 5;
    int x{ y };
    

    Moreover in C++ you can even to make a reference to the variable y the following way

    int &x{ y = 5 };
    

    Here is a demonstrative program

    #include <iostream>
    
    int main() 
    {
        int y;
        int &x{ y = 5 };    
    
        std::cout << "y = " << y << '\n';
    
        x = 10;
    
        std::cout << "y = " << y << '\n';
    }
    

    Its output is

    y = 5
    y = 10
    

    You may this declaration

    int x{ y = 5 };
    

    rewrite also like

    int x = { y = 5 };
    

    However take into account that there is a difference between these (looking similarly as the above declarations) two declarations.

    auto x{ y = 5 };
    

    and

    auto x = { y = 5 };
    

    In the first declaration the variable x has the type int. In the second declaration the variable x has the type std::initializer_list<int>.

    To make the difference more visible see how the values of the objects are outputted.

    #include <iostream>
    
    int main() 
    {
        int y;
        auto x1 { y = 5 };  
    
        std::cout << "x1 = " << x1 << '\n';
    
        auto x2 = { y = 10 };   
    
        std::cout << "*x2.begin()= " << *x2.begin() << '\n';
    
        std::cout << "y = " << y << '\n';
    
        return 0;
    }
    

    The program output is

    x1 = 5
    *x2.begin()= 10
    y = 10