Boost logo

Boost :

Subject: Re: [boost] [variant] match()
From: Matt Calabrese (rivorus_at_[hidden])
Date: 2015-01-07 13:40:44


On Wed, Jan 7, 2015 at 12:41 AM, Eelis <eelis_at_[hidden]> wrote:

> Boost.Variant provides access through get() and visitors, but in C++11 we
> can do so much better! :)
>
> For a boost::variant<A,B,C>, the attached small utility function match()
> lets you write:
>
> match(v,
> [](A & a){ cout << "it's a A!"; }
> [](B & b){ cout << "oh, a B!"; }
> [](C & c){ cout << "ah yes, a C!"; });
>
> Return values are supported. I think this really belongs in Boost. It
> makes variants much more usable.
>
> Regards,
>
> Eelis

This has come up before in various contexts. I'm not a fan of "match" as it
is implemented here for a few of reasons:
* It does not allow one or more of the functions to work with multiple
elements (I.E. if one of them is an lambda with an auto parameter).
* It does not currently scale to n-ary visitation.
* This implementation is linear and uses variant's get rather than simply
re-using apply_visitor.
* Directly common_type is probably not what you want here due to its
behavior regarding references and because it is potentially order-dependent.

My personal stance and I what I use on projects is something a little
different and I try to evangelize: Make an overloads template that just
works with apply_visitor or an apply_visitor like function:

apply_visitor( overloads( [](A & a){ cout << "it's a A!"; }
                          [](B & b){ cout << "oh, a B!"; }
                          [](C & c){ cout << "ah yes, a C!"; }
                          [](auto & d){ cout << "a default!"; }
                        ),

               v

             );

All overloads does is make a visitor that contains an overload set of all
of the passed-in function objects (done by base classes and bringing in the
operator() functions from each base). Instead of this solution having its
own dispatching mechanism it just works via apply_visitor so it has exactly
the known behavior and works fine with n-ary visitation out of the box.
Overload resolution is exactly C++ overload resolution in an overload set
because each passing in function object's operator() is brought in through
a using-declaration. Function objects that are function pointers are
handled as well via internal wrapping.

The main limitation of this approach is that overloads must copy/move the
passed-in function objects. I.E. there is no known tie_overloads that would
be able to exhibit the same behavior.

-- 
-Matt Calabrese

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk