Boost logo

Boost Users :

From: Steven Watanabe (steven_at_[hidden])
Date: 2008-01-09 13:50:52


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


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net