Joel de Guzman wrote:
Tobias Schwinger wrote:
Then 'switch_<void>(n)' is a fused function and 'cases' a sequence of cases (whether implemented with Fusion or not)...
The number of cases *can* vary at compile time. I have a guess that we're talking past each other.
Yes, obviously -- I think because of a pair of parentheses. This code
switch_<result>(n) (( // ... hand-written cases, note (( ));
would've told me more easily what you're up to :-). )) I often add the double parens. Someone asked why at BoostCon'07. I answered "because I like it" :-) Now, I have a more valid reason. Yeah... sorry about the confusion.
Never mind! This way we "emulated" some additional reviewers producing a lot of noise ;-).
For the purpose of clarification, let me call the original interface A and my proposal B.
Again:
* Transforming A to B requires minimal amount of coding. The smarts is already in the PP code. The cost is cheap. The cost is cheap and the effect is destructive :-).
Why is it destructive?
We lose the index and the chance to easily use a single function for all cases.
Index:
* I also recall sometime ago when attributes for Spirit2 was being discussed. For alternates:
(a | b | c)[f]
the question was: do f receive the index or not. Many times it is useful.
* With for_each (and many of the algorithms), one disadvantage over the lowly for or while is the access to the index of the iterator. Many times those are usefule too.
My answer to these kind of concerns now is: bind it when you need it.
Single function:
I'm a strong advocate of smaller is better. Modularity matters. Big classes (or in this case function objects), metaprogram blobs (i.e. traits), humongous enums, and all such sort of dinosours :-) are best avoided. They are convenient up to a certain extent and becomes unmanageable beyond a certain limit.
In all of my use cases, I have N functions that are provided elsewhere and I have no control over (e.g. parser functions). I insist that this is the more common use case. Grouping them into a single big struct is an unnecessary and cumbersome step.
Still, if people insist, I outlined a way to convert the big function object to smaller 'bound' objects, in another post. Just bind 'em into smaller function chunks.
I think it's a misconception to assume that a single function object will be inherently big. It's just another degree of freedom (namely what to look up) exposed to the user. Whether one can appreciate it seems a matter of taste to me...
A ---> B: function := L(I): functions[I]() B ---> A: transform(cases, L(I): make_pair<I>(bind(function,I())))
...and I happen to prefer the first transform.
// Notation: // ========= // uppercase - types // lowercase - objects // L(args): - lambda composition
I don't expect us to a reach consensus, but hopefully we do understand each other's points now.
That's a relief ;-)
So it wasn't all for nothing :-P...
Now that that's cleared, let me /push/ now the other benefits of my proposed interface:
* Ability to allow fall-through and break:
case_<1>(f1, break_), // no fall-through case_<2>(f2), // fall-through (by default)
* Allow multiple case handling:
case_<'x', 'y'>(f2), // handle 'x' and 'y'
This stuff is pretty cool. But it -again- makes me think we are in fact talking about two different kinds of switch tools: One that can be used manually with lots of syntactic sugar - and another one that's mean and lean and doesn't have to be that pretty because it's intended to be fed its input in form of an automatically computed sequence, anyway... Regards, Tobias