
AMDG Joel de Guzman <joel <at> boost-consulting.com> writes:
Here's my review:
* What is your evaluation of the design?
It's a very simple design. Very straightforward. I'm not quite sure about the interface though:
* The specification of cases is a bit cumbersome. In the common case, they are both specified in the switch_ call and in the individual function call overloads supplied by the client (e.g.):
1) switch_<mpl::vector_c<int, 1, 2, 3> >(n, f) 2) void F::operator()(mpl::int_<1>) void F::operator()(mpl::int_<2>) void F::operator()(mpl::int_<3>)
Redundant.
If that's how you're using it yes it's redundant. There are really two use cases. One is basically what you are asking for. Separate functions for each case. The other is when you have a runtime integer and somehow want to get back to compile time. The first example I can think of off the top of my head is using switch_ to implement variant. It's pretty straightforward with the mpl sequence interface: template<class Variant, class Visitor> struct visitor_applier { typedef typename Visitor::result_type result_type; template<class N> result_type operator()(N) { visitor( variant.get<typename mpl::at<typename variant::types, N>::type>()); } Visitor& visitor; Variant& variant; }; template<class Variant, class Visitor> typename Visitor::result_type apply_visitor(Visitor visitor, Variant& variant) { visitor_applier<Variant, Visitor> impl = { visitor, variant }; return switch< mpl::range_c<int, 0, mpl::size<typename Variant::types>::value> >(variant.which(), impl); } To implement this with separate functions for each case requires the additional complexity of somehow collecting all the cases together. For this even to be possible, I would have to use a fusion sequence. Something along the lines of switch_<result_type>(n, *make_tuple(* case<1>(f1), case<2>(f2), ... )) It's possible to implement this in terms of the interface I chose and vise versa. Either one is inconvenient for some tasks. I optimized the interface for the uses that I understood best.
* I'd prefer the result type to be user-specified like in Boost.Bind instead of hard-wiring it to F::result_type.
Ok.
* The client needs to provide a specialized function object for the case detection. There's no way to use plain functions or even Boost.Function.
I've implemented switch_ many times now. Here are some links: http://tinyurl.com/28e8y2 and http://tinyurl.com/ypmgob
Having said all that, my preferred syntax is:
switch_<return_type>(n, case_<1>(f1), case_<2>(f2), case_<3>(f3), default_(fd) );
<snip>
The most important disadvantage which makes it a no-go for me is that the number of cases is hard-wired into the program structure. In short, this makes it so much like the native switch statement that there is little benefit to using it.
Not at the moment. I think we need a more thorough discussion on alternative interfaces. We also need to discuss the issues that were raised in the review. I'm eager to hear Steven's replies. He seem to be a bit too quiet?
Sorry. A lot of the messages haven't been appearing on GMane... Thanks a lot for your review, Joel. In Christ, Steven Watanabe