the cast on zero seems kind of nuts. Does that serve some purpose?
The void cast on 0 is probably so it matches the void on the other possible value of the conditional operator; I think both values are supposed to be of the same type, although void is a strange type.
To OP:
Overall I feel the void casts are pointless and unnecessary here.
Where did you get this code?
Reading has more to do with pattern recognition then it does straight up see what's there
and translate. Introducing weird patterns like this slows people down without actually making it any easier to read. If this were a common pattern, people would get used to it. But I don't think I have ever seen a ternary written like this before.
In case it isn't clear, I agree with the others that this should be avoided. Ha, haha... Apparently it used to be helpful with old static analysis tools. But, I too, have never actually seen it used in code, modern or old, and agree it would add more confusion without any benefit.
With regard to splitting the ternary like that: On one hand splitting things where there are sub-expressions is sometimes helpful ; on the other hand it does seem confusing, for me because of the mismatch in parentheses on line 6. I know it's because they match the whole ternary from line 4, but it makes it harder to read. Maybe these opening and closing parentheses could be on a line of their own?
@JUAN DENT
What's more confusing is the cast to void of a std:: (?) initializer_list ; and the comma operator with a 0 on line 6.
So the cast to void is a discarded value expression, relying on side effects. But it seems to apply to all of the lambda, what are the side effects?
So what does this code do? Does it call function f when x is less than rest (a parameter pack, ergo a fold expression) but casts it to void, (so what are the side effects of function f ? ) ; else set values to 0.
Also the constexpr at the end of lines 1 and 10, I have never seen that before ?
It would be great to see some input / output for this code.
Was this code from the Template Meta Programming book by Vandervoode & Josuttis ?
What's more confusing is the cast to void of a std:: (?) initializer_list ; and the comma operator with a 0 on line 6.
The purpose of the std::initializer_lists are to sequence the evaluations of the sub-expressions that result from those ellipses. For instance, It makes sure that call_cart() is evaluated in-order WRT the arguments to cartesian(). This is important when arguments have side effects.
Since it's hard to explain without code, here's an example of a similar trick (with int[] instead of initializer_list) being used in context: http://www.cplusplus.com/forum/general/207656/
casting the initializer_list to void avoids compiler warnings.
The constexpr qualifies the lambda - it's a new C++17 feature. Now lambdas can appear in constant expressions (finally.)
Furthermore, we have fold-expressions, which make this trick obsolete:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
#include <iostream>
// wrong: no capture-default allowed for lambdas at namespace scope
constexprauto call_cart = [/* = */](auto f, auto x, auto... rest) constexpr {
(((x < rest) ? (void)f(x, rest) : (void)0), ...);
};
constexprauto cartesian = [/* = */](auto... xs) constexpr {
return [=](auto f) constexpr { (call_cart(f, xs, xs...), ...); };
};
int main() {
auto f = [](auto x, auto y) { std::cout << x << ", " << y << '\n'; };
cartesian(1, 2, 3, 4)(f);
}