Comma operator has the lowest precedence, so I think even if I don't surround parentheses, there should be no problem after expansion. So, why do I have to surround std::cout << args << ' ' with parentheses in this fold expression? I'm using C++17.
Because the standard defines a unary left fold expression as:
( ... fold-operatorcast-expression )
In your case the fold-operator is the comma operator. This is OK.
A cast-expression is one of the following:
unary-expression
( type-id ) cast-expression
The expression std::cout << args << ' ' is not a unary-expression and it doesn't start with a type within parentheses so it's not a cast-expression.
Unary-expressions are things like 123, var, foo(), arr[i]. Any expression that is surrounded by parentheses is also a unary-expression. That's why the parentheses are necessary in your code.