Boost logo

Boost :

Subject: Re: [boost] [variant2] documentation request
From: Gottlob Frege (gottlobfrege_at_[hidden])
Date: 2019-03-03 17:51:21


On Sun, Mar 3, 2019 at 7:39 AM Peter Dimov via Boost
<boost_at_[hidden]> wrote:
>
> Gottlob Frege wrote:
> > For variant<int, short>, can I assign a T that has an operator int()?
> > Is assignment templatized?
> >
> > What happens with
> >
> > struct Bad
> > {
> > operator int() { throw false; }
> > };
> >
> > variant<int, short> v = (short)10;
> > v = Bad();
>
> For the following:
>
> #include "boost/variant2/variant.hpp"
> #include <iostream>
>
> struct Bad
> {
> operator int() { throw false; }
> };
>
> using namespace boost::variant2;
>
> int main()
> {
> variant<int, short> v = (short)10;
>
> try
> {
> v = Bad();
> }
> catch(...)
> {
> std::cout << "Exception\n";
> }
>
> visit([](auto const& x){ std::cout << "(" << typeid(x).name() << ")" <<
> x << std::endl; }, v );
> }
>
> the output is
>
> Exception
> (short)10
>
> There are a number of subtleties here that I haven't quite captured in the
> documentation; I'll see how I can document the behavior properly. The
> assignment itself is
>
> "template<class U> constexpr variant& operator=( U&& u )
> noexcept( /*see below*/ );
>
> Let Tj be a type that is determined as follows: build an imaginary function
> FUN(Ti) for each alternative type Ti. The overload FUN(Tj) selected by
> overload resolution for the expression FUN(std::forward<U>(u)) defines the
> alternative Tj which is the type of the contained value after construction.
>
> Effects:
> If index() == j, assigns std::forward<U>(u) to the value contained in *this.
>
> Otherwise, equivalent to emplace<j>(std::forward<U>(u))."
>
> and that's correct. So in this case index() is not j and it does
> emplace<1>( Bad() ).
>
> The behavior of emplace varies depending on a number of things:
>
> - whether all types are trivially destructible
> - whether the variant is single- or double-buffered
> - whether the type we're constructing is nothrow constructible from the
> arguments
> - whether all contained types are trivially move constructible and move
> assignable
> - and finally, whether, in the single buffered case, we have a monostate
> type
>
> In this specific case, it's trivially destructible, single buffered, int not
> nothrow constructible from Bar, all types trivially move constructible and
> move assignable; so we end up constructing a temporary variant, then
> memcpy-ing it over *this.
>
>

And do you sometimes do the opposite order - memcpy *this to a
temporary, emplace into this, memcpy back from the temporary if
emplace failed?

ie when the current value is trivial, but the new one isn't?

I'd like std::variant to do a few more of these heroics.


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