Search code examples
c++gccclangc++14language-lawyer

What's {} in void({})?


Consider the following snippet:

auto f() { return void({}); }
int main() { f(); }

What's exactly the {} in void({})? How is it interpreted?

Just out of curiosity, of course. Let's go a bit further anyway.

Note that both GCC 6.1 and clang 3.8 compile it with no errors (-std=c++14 -pedantic). The latter doesn't complain, the former shows a warning:

warning: list-initializer for non-class type must not be parenthesized

Using -pedantic-errors instead, GCC ends with an error while clang compiles it.

Is this discrepancy an error of one of the two compilers? I mean, is it valid code that should be accepted or not?


Solution

  • Conversions to void type as well as the possibility to returning a void value have been present in the C++ language since the very beginning. The only part that raises questions is the role of {} in this context.

    A quick experiment with clang

    int a({});
    

    generates an error message saying

    error: cannot initialize a variable of type 'int' with an rvalue of type 'void'

    which indicates that Clang interprets {} as a void value. This appears to be a non-standard behavior. I don't see any place in language specification that would say that {} should produce a void value in this context.

    But since this happens to be the case in clang, there isn't anything unusual in void({}) compiling in clang. Any value in C++ can be converted to void type, meaning that as long as the compiler accepts {} in this context, the rest just follows naturally.

    In GCC, it is actually an error in -pedantic-errors mode:

    error: list-initializer for non-class type must not be parenthesized

    So formally it is an "error", not a "warning" in GCC.


    The combination of opening ({ and closing }) makes these compilers to interpret it as a GNU C language extension known as Statement Expression (which is incidentally supported by clang as well). This is, for example, what makes the following code compile

    int a = ({ 3; });
    

    Under that extension, the expression ({}) is seen as a statement expression of void type. However, this conflicts with the uniform initialization syntax in C++.