Search code examples
c++language-lawyerfold-expression

Does the operand to a fold expression need to be parenthesized?


For the following program:

#include<iostream>

auto f(auto ...args) 
{
    (std::cout << 1 << ... << args);
}

int main()
{
    f(0, 0, 0);
}

gcc prints 1000, but clang gives an error:

error: expression not permitted as operand of fold expression
    (std::cout << 1 << ... << args);
     ~~~~~~~~~~^~~~
     (            )

I'm not sure I understand the error. Adding parentheses like this:

((std::cout << 1) << ... << args);

still seems to be an expression but now clang accepts this as well, and also prints 1000.

Also, the auto parameters for f are irrelevant, the equivalent program written in c++17 has the same behavior (as shown in the demo).

So is the program valid?


Solution

  • The grammar of a fold-expression ([expr.prim.fold]) is:

    fold-expression:

    ( cast-expression fold-operator ... )
    ( ... fold-operator cast-expression )
    ( cast-expression fold-operator ... fold-operator cast-expression )

    You are using the third form. What you want to be parsed as the first cast-expression is a shift-expression ([expr.shift]), but a shift-expression is not a cast-expression, so this is not a valid fold-expression.

    That is, a >> b has lower precedence than (T) c, which is the lowest precedence form that a fold expression can accept. This is because the next highest is a pointer-to-member expression, which is one of the possible fold operators itself so it could be ambiguous.