$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
From: Eric Friedman (ebf_at_[hidden])
Date: 2003-10-20 18:03:45
Brian McNamara wrote:
> On Sun, Oct 19, 2003 at 05:27:24PM -0700, Eric Friedman wrote:
> 
>>This is something I had been working on about two months ago but didn't 
>>post to the sandbox until recently.
> 
> This looks potentially cool, but I don't quite understand it.
Thanks. Hopefully I can clarify...
>>The basic idea is this:
>>
>>  switch_( [variant] )
>>    |= case_< [pattern1] >(...)
>>    |= case_< [pattern2] >(...)
>>    :::
>>    |= default_(...)  // optional catch-all
>>    ;
>>
>>The switch_ will fail to compile if not every case is handled. In terms 
> 
> Given the general form of patterns you describe below, I can't possibly
> imagine how you determine if every case is handled, but for now I'll
> take your word for it.  :)
OK :)
>>of handling, the case_ constructors take typical function objects, 
>>though the switch_ ignores any return values.
> 
> Why ignore return values?  If all cases had the same return type (or
> returns types convertible to one fixed type), could you make the whole
> thing an expression?  Like
> 
>    int x = switch_( [variant] )  // or maybe switch_<int>( [variant] )
>             |= case_< [pattern1] >(...)
>             |= case_< [pattern2] >(...)
>             :::
>             |= default_(...)  // optional catch-all
>             ;
> 
> (The alternate syntax in the comment suggests that you pass the intended
> return type of the whole expression as an argument to switch_, rather
> than try to infer it from all the case arms.)
This should be workable, and I'll look into it. On first glance, I 
prefer the second syntax (i.e., switch_<int>); otherwise I believe the 
switch would need to prefer the result type of the first case. I think 
the first syntax would also cause some difficulty with lambda expressions.
>>An example usage is the following (though I have again left out the 
>>function objects that need to be passed to the case_ constructors):
>>
>>  using namespace boost::type_switch;
>>
>>  variant<
>>      int
>>    , pair<int,double>
>>    , pair<int,int>
>>    , pair<double,int>
>>    > var;
>>
>>  switch_(var)
>>    |= case_< pair<_1,_1> >(...) // matches pair<int,int>
>>    |= case_< pair<int,_> >(...) // matches pair<int,*>
>>    |= case_< pair<_,_> >(...)   // matches pair<*,*>
>>    |= case_< int >(...)
>>    ;
> 
> 
> So to make sure I understand, inside the ellipsis here:
> 
>    |= case_< pair<_1,_1> >(...) // matches pair<int,int>
> 
> I'd put a function object that knows how to accept pairs and do
> something?  Like "pp" in
> 
>    struct PairPrinter {
>       template <class T, class U>
>       void operator()( pair<T,U> p ) const {
>          cout << p.first << p.second << endl;
>       }
>    } pp;
> 
> that code?
Yes, that's the idea. Note that lambda functions work, too.
>>The pattern matching is implemented in terms of lambda_match, which I 
>>have also added to the sandbox (to boost/mpl). Notably, lambda_match 
>>leverages the MPL lambda workarounds for deficient compilers, extending 
>>the applicability of type_switch somewhat.
> 
> 
> Does the pattern matching only know about a fixed set of types (like
> pair)?  Or does it work on any template?
Assuming a conformant compiler, pattern matching works on any template 
whose arity is under some implementation-defined limit (currently tied 
to the MPL preprocessor symbol BOOST_MPL_METAFUNCTION_MAX_ARITY, which 
is 5). With true variadic template parameter lists, this arity 
restriction could be removed.
On a compiler without partial specialization and template template 
parameters, it works only on templates that have the appropriate MPL 
lambda_support workarounds (i.e., very few templates). Again, maximum 
arity is limited.
Eric