Boost logo

Boost :

From: Robert Ramey (ramey_at_[hidden])
Date: 2019-05-30 23:50:32


On 5/30/19 4:17 PM, Gottlob Frege via Boost wrote:

>
> I'm going to say *most* classes have a throwing move operators.
> Why? Because most classes have a custom copy constructor (because
> people don't follow Rule of Zero like they should),
> and thus most classes don't have *any* move operations.
>
> So all the move operations are actually copy operations, and most of
> those classes have a string or vector or whatever, and can throw on
> copy.
>
> Now, having said that, none of those classes actually throw in "real
> life", because they only throw when memory is completely exhausted,
> and have probably crashed already.
> And on some systems that oversubscribe allocation, they don't throw at
> all, they just crash.
>
> Thus most move operators, whether they exist or not, don't really throw.

This rather illustrates my point. As it stands now we've got
std::variant, boost::variant and boost::variant2. And while we're at it
don't for get std::optional, boost::optional, boost::outcome,
std::expected? and ...?

I don't think there's an general expectation that any of these are going
to interoperate - but they might by accident.

  So I need one of these - or maybe something very similar. As a user
I'm now tasked with a mini-research project to figure out which one I
want. OK, not too bad. But also which might be incompatible with the
types T I'm going to want to use. Or which might have a surprising
throw when I use them.

One approach is yours, carefully design the particular type of variant
with the features that we expect users will require. This will never
result in agreement and some compromise will have to be reached. And
this compromise will surely contain subtle points that the user will
need to research and understand in order to code which is clearly correct.

So I'm all for giving up. Encapsulate the debates/tradoffs into the
list of policy parameters and in type requirements for the type. So
effectively we'll have:

template<
   variant_requirements_on_T<bool is_assignable, iscopyable,
is_moveable, is_no_throw, is_default_constructible, ...>, // list of
restrictions of behavior of the variant being created
   class T ... // list of types in the union
>
struct mother_of_all_variants {
...
};

This type would trap at compile time any attempts instantiate at type
which violates the specified requirements. This is what the user
actually needs in order to write a program that he can have confidence in.

And of course we'd have
template<class T>
using optional = mother_all_variants< ..., bool>

to avoid the necessity to do any actual thinking at all.

Aside - I'm not crazy about the naming "basic_variant" as I don't think
it does justice to the brilliance of the concept. But I recognize that
such naming is much in line with historical practice and users
expectations so I see the merit in "basic_variant".

Aside2 - can one imagine the satisfaction to be derived from knowing
that forever more, we won't be subject to any more arcane debates on
what behavior some variant class should support?

Robert Ramey

>
> _______________________________________________
> Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
>


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