This is not standard C++. This is a GCC extension known as statement expression. A compound statement enclosed in parentheses can appear where an expression is allowed. If the last statement in the brace-enclosed block is an expression statement, then the value of this expression is also the value of the overall statement expression; otherwise, the statement expression is of type void
and has no value.
Your first example is roughly equivalent to
([](){ return S<1>(), S<2>(); })();
(that's a lambda that's created and then called immediately). There's a comma expression that creates S<1>
and S<2>
temporaries. S<1>
is destroyed, S<2>
is, technically, copied to the return value - but that copy is elided. If it weren't for this copy elision, you'd see
S<1>()
S<2>()
S<2>(S<2>&&) // (1) move constructor
~S<2>() // (2) the original temporary is destroyed
~S<1>()
~S<2>() // the copy is destroyed outside of the lambda
But the pair (1)/(2) is elided, leaving the sequence you observe in your example.
In the second example, the last statement within the braces is not an expression, so the whole thing doesn't have a value either. It's roughly equivalent to
([](){ S<3>(), S<4>(); return; })();
Both temporaries are created and destroyed within the lambda, and the usual rules apply - temporaries are destroyed in the reverse order of construction.