Boost logo

Boost :

Subject: Re: [boost] [variant2] documentation request
From: Peter Dimov (lists_at_[hidden])
Date: 2019-03-03 12:39:06


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.


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