diff --git a/doc/.gitignore b/doc/.gitignore index 334f513..ff8f381 100644 --- a/doc/.gitignore +++ b/doc/.gitignore @@ -1 +1,2 @@ /pdf/ +/html/ diff --git a/doc/html/variant2.html b/doc/html/variant2.html deleted file mode 100644 index 2d54afd..0000000 --- a/doc/html/variant2.html +++ /dev/null @@ -1,2798 +0,0 @@ - - - - - - - - -Boost.Variant2: A never valueless variant type - - - - - -
-
-

Overview

-
-
-

Description

-
-

This library implements a type-safe discriminated/tagged union type, -variant<T…​>, that is API-compatible with the C++17 Standard’s -std::variant<T…​>.

-
-
-

A variant<T1, T2, …​, Tn> variable can hold a value of any of the -types T1, T2, …​, Tn. For example, -variant<int64_t, double, std::string> can hold an int64_t value, a -double value, or a string value.

-
-
-

Such a type is sometimes called a "tagged union", because it’s roughly -equivalent to

-
-
-
-
struct V
-{
-    enum tag { tag_int64_t, tag_double, tag_string };
-
-    tag tag_;
-
-    union
-    {
-        int64_t     i_;
-        double      d_;
-        std::string s_;
-    };
-};
-
-
-
-
-

Usage Examples

-
-

Variants can be used to represent dynamically-typed values. A configuration -file of the form

-
-
-
-
server.host=test.example.com
-server.port=9174
-cache.max_load=0.7
-
-
-
-

can be represented as std::map<std::string, variant<int64_t, double, -std::string>>.

-
-
-

Variants can also represent polymorphism. To take a classic example, a -polymorphic collection of shapes:

-
-
-
-
#define _USE_MATH_DEFINES
-#include <iostream>
-#include <vector>
-#include <memory>
-#include <cmath>
-
-class Shape
-{
-public:
-
-    virtual ~Shape() = default;
-    virtual double area() const = 0;
-};
-
-class Rectangle: public Shape
-{
-private:
-
-    double width_, height_;
-
-public:
-
-    Rectangle( double width, double height ):
-        width_( width ), height_( height ) {}
-
-    virtual double area() const { return width_ * height_; }
-};
-
-class Circle: public Shape
-{
-private:
-
-    double radius_;
-
-public:
-
-    explicit Circle( double radius ): radius_( radius ) {}
-    virtual double area() const { return M_PI * radius_ * radius_; }
-};
-
-double total_area( std::vector<std::unique_ptr<Shape>> const & v )
-{
-    double s = 0.0;
-
-    for( auto const& p: v )
-    {
-        s += p->area();
-    }
-
-    return s;
-}
-
-int main()
-{
-    std::vector<std::unique_ptr<Shape>> v;
-
-    v.push_back( std::unique_ptr<Shape>( new Circle( 1.0 ) ) );
-    v.push_back( std::unique_ptr<Shape>( new Rectangle( 2.0, 3.0 ) ) );
-
-    std::cout << "Total area: " << total_area( v ) << std::endl;
-}
-
-
-
-

can instead be represented as a collection of variant<Rectangle, Circle> -values. This requires the possible Shape types be known in advance, as is -often the case. In return, we no longer need virtual functions, or to allocate -the values on the heap with new Rectangle and new Circle:

-
-
-
-
#define _USE_MATH_DEFINES
-#include <iostream>
-#include <vector>
-#include <cmath>
-
-#include <boost/variant2/variant.hpp>
-using namespace boost::variant2;
-
-struct Rectangle
-{
-    double width_, height_;
-    double area() const { return width_ * height_; }
-};
-
-struct Circle
-{
-    double radius_;
-    double area() const { return M_PI * radius_ * radius_; }
-};
-
-double total_area( std::vector<variant<Rectangle, Circle>> const & v )
-{
-    double s = 0.0;
-
-    for( auto const& x: v )
-    {
-        s += visit( []( auto const& y ){ return y.area(); }, x );
-    }
-
-    return s;
-}
-
-int main()
-{
-    std::vector<variant<Rectangle, Circle>> v;
-
-    v.push_back( Circle{ 1.0 } );
-    v.push_back( Rectangle{ 2.0, 3.0 } );
-
-    std::cout << "Total area: " << total_area( v ) << std::endl;
-}
-
-
-
-
-

Construction and Assignment

-
-

If we look at the

-
-
-
-
    v.push_back( Circle{ 1.0 } );
-
-
-
-

line, we can deduce that variant<Rectangle, Circle> can be (implicitly) -constructed from Circle (and Rectangle), and indeed it can. It can also -be assigned a Circle or a Rectangle:

-
-
-
-
variant<Rectangle, Circle> v = Circle{ 1.0 }; // v holds Circle
-v = Rectangle{ 2.0, 3.0 };                    // v now holds Rectangle
-
-
-
-

If we try to construct variant<int, float> from something that is neither -int nor float, say, (short)1, the behavior is "as if" the variant has -declared two constructors,

-
-
-
-
variant::variant(int x);
-variant::variant(float x);
-
-
-
-

and the standard overload resolution rules are used to pick the one that will -be used. So variant<int, float>((short)1) will hold an int.

-
-
-
-

Inspecting the Value

-
-

Putting values into a variant is easy, but taking them out is necessarily a -bit more convoluted. It’s not possible for variant<int, float> to define a -member function get() const, because such a function will need its return -type fixed at compile time, and whether the correct return type is int or -float will only become known at run time.

-
-
-

There are a few ways around that. First, there is the accessor member function

-
-
-
-
std::size_t variant::index() const noexcept;
-
-
-
-

that returns the zero-based index of the current type. For variant<int, -float>, it will return 0 for int and 1 for float.

-
-
-

Once we have the index, we can use the free function get<N> to obtain the -value. Since we’re passing the type index to get, it knows what to return. -get<0>(v) will return int, and get<1>(v) will return float:

-
-
-
-
void f( variant<int, float> const& v )
-{
-    switch( v.index() )
-    {
-    case 0:
-
-        // use get<0>(v)
-        break;
-
-    case 1:
-
-        // use get<1>(v)
-        break;
-
-    default:
-
-        assert(false); // never happens
-    }
-}
-
-
-
-

If we call get<0>(v), and v.index() is not currently 0, an exception -(of type bad_variant_access) will be thrown.

-
-
-

An alternative approach is to use get<int>(v) or get<float>(v). This -works similarly.

-
-
-

Another alternative that avoids the possibility of bad_variant_access is -to use get_if. Instead of a reference to the contained value, it returns -a pointer to it, returning nullptr to indicate type mismatch. get_if -takes a pointer to the variant, so in our example we’ll use something along -the following lines:

-
-
-
-
void f( variant<int, float> const& v )
-{
-    if( int const * p = get_if<int>(&v) )
-    {
-        // use *p
-    }
-    else if( float const * p = get_if<float>(&v) )
-    {
-        // use *p
-    }
-    else
-    {
-        assert(false); // never happens
-    }
-}
-
-
-
-
-

Visitation

-
-

Last but not least, there’s visit. visit(f, v) calls the a function object -f with the value contained in the variant v and returns the result. When -v is variant<int, float>, it will call f with either an int or a -float. The function object must be prepared to accept both.

-
-
-

In practice, this can be achieved by having the function take a type that can -be passed either int or float, such as double:

-
-
-
-
double f( double x ) { return x; }
-
-double g( variant<int, float> const& v )
-{
-    return visit( f, v );
-}
-
-
-
-

By using a function object with an overloaded operator():

-
-
-
-
struct F
-{
-    void operator()(int x) const { /* use x */ }
-    void operator()(float x) const { /* use x */ }
-};
-
-void g( variant<int, float> const& v )
-{
-    visit( F(), v );
-}
-
-
-
-

Or by using a polymorphic lambda, as we did in our Circle/Rectangle -example:

-
-
-
-
void g( variant<int, float> const& v )
-{
-    visit( [&]( auto const& x ){ std::cout << x << std::endl; }, v );
-}
-
-
-
-

visit can also take more than one variant. visit(f, v1, v2) calls -f(x1, x2), where x1 is the value contained in v1 and x2 is the value -in v2.

-
-
-
-

Default Construction

-
-

The default constructor of variant value-initializes the first type in -the list. variant<int, float>{} holds 0 (of type int), and -variant<float, int>{} holds 0.0f.

-
-
-

This is usually the desired behavior. However, in cases such as -variant<std::mutex, std::recursive_mutex>, one might legitimately wish to -avoid constructing a std::mutex by default. A provided type, monostate, -can be used as the first type in those scenarios. variant<monostate, -std::mutex, std::recursive_mutex> will default-construct a monostate, -which is basically a no-op, as monostate is effectively an empty struct.

-
-
-
-
-
-

Revision History

-
-
-

Changes in 1.71.0

-
-

After the Boost formal review, the implementation has been -changed to provide the strong exception safety guarantee, -instead of basic. expected has been removed.

-
-
-
-
-
-

Design

-
-
-

Features

-
-

This variant implementation has two distinguishing features:

-
-
-
    -
  • -

    It’s never "valueless", that is, variant<T1, T2, …​, Tn> has an -invariant that it always contains a valid value of one of the types -T1, T2, …​, Tn.

    -
  • -
  • -

    It provides the strong exception safety guarantee on assignment and -emplace.

    -
  • -
-
-
-

This is achieved with the use of double storage, unless all of the -contained types have a non-throwing move constructor.

-
-
-
-

Rationale

-
-

Never Valueless

-
-

It makes intuitive sense that variant<X, Y, Z> can hold only values -of type X, type Y, or type Z, and nothing else.

-
-
-

If we think of variant as an extension of union, since a union -has a state called "no active member", an argument can be made that a -variant<X, Y, Z> should also have such an additional state, holding -none of X, Y, Z.

-
-
-

This however makes variant less convenient in practice and less useful -as a building block. If we really need a variable that only holds X, -Y, or Z, the additional empty state creates complications that need -to be worked around. And in the case where we do need this additional -empty state, we can just use variant<empty, X, Y, Z>, with a suitable -struct empty {};.

-
-
-

From a pure design perspective, the case for no additional empty state is -solid. Implementation considerations, however, argue otherwise.

-
-
-

When we replace the current value of the variant (of, say, type X) with -another (of type Y), since the new value needs to occupy the same storage -as the old one, we need to destroy the old X first, then construct a new -Y in its place. But since this is C++, the construction can fail with an -exception. At this point the variant is in the "has no active member" -state that we’ve agreed it cannot be in.

-
-
-

This is a legitimate problem, and it is this problem that makes having -an empty/valueless state so appealing. We just leave the variant empty on -exception and we’re done.

-
-
-

As explained, though, this is undesirable from a design perspective as it -makes the component less useful and less elegant.

-
-
-

There are several ways around the issue. The most straightforward one is to -just disallow types whose construction can throw. Since we can always create -a temporary value first, then use the move constructor to initialize the one -in the variant, it’s enough to require a nonthrowing move constructor, -rather than all constructors to be nonthrowing.

-
-
-

Unfortunately, under at least one popular standard library implementation, -node based containers such as std::list and std::map have a potentially -throwing move constructor. Disallowing variant<X, std::map<Y, Z>> is hardly -practical, so the exceptional case cannot be avoided.

-
-
-

On exception, we could also construct some other value, leaving the variant -valid; but in the general case, that construction can also throw. If one of -the types has a nonthrowing default constructor, we can use it; but if not, -we can’t.

-
-
-

The approach Boost.Variant takes here is to allocate a temporary copy of -the value on the heap. On exception, a pointer to that temporary copy can be -stored into the variant. Pointer operations don’t throw.

-
-
-

Another option is to use double buffering. If our variant occupies twice -the storage, we can construct the new value in the unused half, then, once -the construction succeeds, destroy the old value in the other half.

-
-
-

When std::variant was standardized, none of those approaches was deemed -palatable, as all of them either introduce overhead or are too restrictive -with respect to the types a variant can contain. So as a compromise, -std::variant took a way that can (noncharitably) be described as "having -your cake and eating it too."

-
-
-

Since the described exceptional situation is relatively rare, std::variant -has a special case, called "valueless", into which it goes on exception, -but the interface acknowledges its existence as little as possible, allowing -users to pretend that it doesn’t exist.

-
-
-

This is, arguably, not that bad from a practical point of view, but it leaves -many of us wanting. Rare states that "never" occur are undertested and when -that "never" actually happens, it’s usually in the most inconvenient of times.

-
-
-

This implementation does not follow std::variant; it statically guarantees -that variant is never in a valueless state. The function -valueless_by_exception is provided for compatibility, but it always returns -false.

-
-
-

Instead, if the contained types are such that it’s not possible to avoid an -exceptional situation when changing the contained value, double storage is -used.

-
-
-
-

Strong Exception Safety

-
-

The initial submission only provided the basic exception safety guarantee. -If an attempt to change the contained value (via assignment or emplace) -failed with an exception, and a type with a nonthrowing default constructor -existed among the alternatives, a value of that type was created into the -variant. The upside of this decision was that double storage was needed -less frequently.

-
-
-

The reviewers were fairly united in hating it. Constructing a random type -was deemed too unpredictable and not complying with the spirit of the -basic guarantee. The default constructor of the chosen type, even if -nonthrowing, may still have undesirable side effects. Or, if not that, a -value of that type may have special significance for the surrounding code. -Therefore, some argued, the variant should either remain with its -old value, or transition into the new one, without synthesizing other -states.

-
-
-

At the other side of the spectrum, there were those who considered double -storage unacceptable. But they considered it unacceptable in principle, -regardless of the frequency with which it was used.

-
-
-

As a result, providing the strong exception safety guarantee on assignment -and emplace was declared an acceptance condition.

-
-
-

In retrospect, this was the right decision. The reason the strong guarantee -is generally not provided is because it doesn’t compose. When X and Y -provide the basic guarantee on assignment, so does struct { X x; Y y; };. -Similarly, when X and Y have nonthrowing assignments, so does the -struct. But this doesn’t hold for the strong guarantee.

-
-
-

The usual practice is to provide the basic guarantee on assignment and -let the user synthesize a "strong" assignment out of either a nonthrowing -swap or a nonthrowing move assignment. That is, given x1 and x2 of -type X, instead of the "basic" x1 = x2;, use either X(x2).swap(x1); -or x1 = X(x2);.

-
-
-

Nearly all types provide a nonthrowing swap or a nonthrowing move -assignment, so this works well. Nearly all, except variant, which in the -general case has neither a nonthrowing swap nor a nonthrowing move -assignment. If variant does not provide the strong guarantee itself, it’s -impossible for the user to synthesize it.

-
-
-

So it should, and so it does.

-
-
-
-
-

Differences with std::variant

-
-

The main differences between this implementation and std::variant are:

-
-
-
    -
  • -

    No valueless-by-exception state: valueless_by_exception() always -returns false.

    -
  • -
  • -

    Strong exception safety guarantee on assignment and emplace.

    -
  • -
  • -

    emplace first constructs the new value and then destroys the old one; -in the single storage case, this translates to constructing a temporary -and then moving it into place.

    -
  • -
  • -

    A converting constructor from, e.g. variant<int, float> to -variant<float, double, int> is provided as an extension.

    -
  • -
  • -

    The reverse operation, going from variant<float, double, int> to -variant<int, float> is provided as the member function subset<U…​>. -(This operation can throw if the current state of the variant cannot be -represented.)

    -
  • -
  • -

    variant<T…​> is not (yet) trivial when all contained types are trivial, -as mandated by C++17.

    -
  • -
  • -

    The C++20 additions and changes to std::variant have not yet been -implemented.

    -
  • -
-
-
-
-

Differences with Boost.Variant

-
-

This library is API compatible with std::variant. As such, its interface -is different from Boost.Variant’s. For example, visitation is performed via -visit instead of apply_visitor.

-
-
-

Recursive variants are not supported.

-
-
-

Double storage is used instead of temporary heap backup. This variant is -always "stack-based", it never allocates, and never throws bad_alloc on -its own.

-
-
-
-
-
-

Implementation

-
-
-

Dependencies

-
-

This implementation only depends on Boost.Config and Boost.Mp11.

-
-
-
-

Supported Compilers

-
-
    -
  • -

    GCC 4.8 or later with -std=c++11 or above

    -
  • -
  • -

    Clang 3.5 or later with -std=c++11 or above

    -
  • -
  • -

    Visual Studio 2015, 2017, 2019

    -
  • -
-
-
-

Tested on Travis and -Appveyor.

-
-
-
-
-
-

Reference

-
-
-

<boost/variant2/variant.hpp>

-
-

Synopsis

-
-
-
namespace boost {
-namespace variant2 {
-
-// in_place_type
-
-template<class T> struct in_place_type_t {};
-template<class T> constexpr in_place_type_t<T> in_place_type{};
-
-// in_place_index
-
-template<std::size_t I> struct in_place_index_t {};
-template<std::size_t I> constexpr in_place_index_t<I> in_place_index{};
-
-// variant
-
-template<class... T> class variant;
-
-// variant_size
-
-template<class T> struct variant_size {};
-
-template<class T> struct variant_size<T const>: variant_size<T> {};
-template<class T> struct variant_size<T volatile>: variant_size<T> {};
-template<class T> struct variant_size<T const volatile>: variant_size<T> {};
-
-template<class T> struct variant_size<T&>: variant_size<T> {}; // extension
-template<class T> struct variant_size<T&&>: variant_size<T> {}; // extension
-
-template<class T>
-  inline constexpr size_t variant_size_v = variant_size<T>::value;
-
-template<class... T>
-  struct variant_size<variant<T...>>:
-    std::integral_constant<std::size_t, sizeof...(T)> {};
-
-// variant_alternative
-
-template<size_t I, class T> struct variant_alternative {};
-
-template<size_t I, class T> struct variant_alternative<I, T const>;
-template<size_t I, class T> struct variant_alternative<I, T volatile>;
-template<size_t I, class T> struct variant_alternative<I, T const volatile>;
-
-template<size_t I, class T> struct variant_alternative<I, T&>; // extension
-template<size_t I, class T> struct variant_alternative<I, T&&>; // extension
-
-template<size_t I, class T>
-  using variant_alternative_t = typename variant_alternative<I, T>::type;
-
-template<size_t I, class... T>
-  struct variant_alternative<I, variant<T...>>;
-
-// variant_npos
-
-constexpr std::size_t variant_npos = -1;
-
-// holds_alternative
-
-template<class U, class... T>
-  constexpr bool holds_alternative(const variant<T...>& v) noexcept;
-
-// get
-
-template<size_t I, class... T>
-  constexpr variant_alternative_t<I, variant<T...>>&
-    get(variant<T...>& v);
-template<size_t I, class... T>
-  constexpr variant_alternative_t<I, variant<T...>>&&
-    get(variant<T...>&& v);
-template<size_t I, class... T>
-  constexpr const variant_alternative_t<I, variant<T...>>&
-    get(const variant<T...>& v);
-template<size_t I, class... T>
-  constexpr const variant_alternative_t<I, variant<T...>>&&
-    get(const variant<T...>&& v);
-
-template<class U, class... T>
-  constexpr U& get(variant<T...>& v);
-template<class U, class... T>
-  constexpr U&& get(variant<T...>&& v);
-template<class U, class... T>
-  constexpr const U& get(const variant<T...>& v);
-template<class U, class... T>
-  constexpr const U&& get(const variant<T...>&& v);
-
-// get_if
-
-template<size_t I, class... T>
-  constexpr add_pointer_t<variant_alternative_t<I, variant<T...>>>
-    get_if(variant<T...>* v) noexcept;
-template<size_t I, class... T>
-  constexpr add_pointer_t<const variant_alternative_t<I, variant<T...>>>
-    get_if(const variant<T...>* v) noexcept;
-
-template<class U, class... T>
-  constexpr add_pointer_t<U>
-    get_if(variant<T...>* v) noexcept;
-template<class U, class... T>
-  constexpr add_pointer_t<const U>
-    get_if(const variant<T...>* v) noexcept;
-
-// relational operators
-
-template<class... T>
-  constexpr bool operator==(const variant<T...>& v, const variant<T...>& w);
-template<class... T>
-  constexpr bool operator!=(const variant<T...>& v, const variant<T...>& w);
-template<class... T>
-  constexpr bool operator<(const variant<T...>& v, const variant<T...>& w);
-template<class... T>
-  constexpr bool operator>(const variant<T...>& v, const variant<T...>& w);
-template<class... T>
-  constexpr bool operator<=(const variant<T...>& v, const variant<T...>& w);
-template<class... T>
-  constexpr bool operator>=(const variant<T...>& v, const variant<T...>& w);
-
-// visit
-
-template<class F, class... V>
-  constexpr /*see below*/ visit(F&& f, V&&... v);
-
-// monostate
-
-struct monostate {};
-
-constexpr bool operator==(monostate, monostate) noexcept { return true; }
-constexpr bool operator!=(monostate, monostate) noexcept { return false; }
-constexpr bool operator<(monostate, monostate) noexcept { return false; }
-constexpr bool operator>(monostate, monostate) noexcept { return false; }
-constexpr bool operator<=(monostate, monostate) noexcept { return true; }
-constexpr bool operator>=(monostate, monostate) noexcept { return true; }
-
-// swap
-
-template<class... T>
-  void swap(variant<T...>& v, variant<T...>& w) noexcept( /*see below*/ );
-
-// bad_variant_access
-
-class bad_variant_access;
-
-} // namespace variant2
-} // namespace boost
-
-
-
-
-

variant

-
-
-
namespace boost {
-namespace variant2 {
-
-template<class... T> class variant
-{
-public:
-
-  // constructors
-
-  constexpr variant() noexcept( /*see below*/ );
-
-  constexpr variant( variant const & r ) noexcept( /*see below*/ );
-  constexpr variant( variant&& r ) noexcept( /*see below*/ );
-
-  template<class U>
-    constexpr variant( U&& u ) noexcept( /*see below*/ );
-
-  template<class U, class... A>
-    constexpr explicit variant( in_place_type_t<U>, A&&... a );
-  template<class U, class V, class... A>
-    constexpr explicit variant( in_place_type_t<U>,
-      std::initializer_list<V> il, A&&... a );
-
-  template<size_t I, class... A>
-    constexpr explicit variant( in_place_index_t<I>, A&&... a );
-  template<size_t I, class V, class... A>
-    constexpr explicit variant( in_place_index_t<I>,
-      std::initializer_list<V> il, A&&... a );
-
-  // destructor
-
-  ~variant();
-
-  // assignment
-
-  constexpr variant& operator=( variant const & r ) noexcept( /*see below*/ );
-  constexpr variant& operator=( variant&& r ) noexcept( /*see below*/ );
-
-  template<class U> constexpr variant& operator=( U&& u ) noexcept( /*see below*/ );
-
-  // modifiers
-
-  template<class U, class... A>
-    constexpr U& emplace( A&&... a );
-  template<class U, class V, class... A>
-    constexpr U& emplace( std::initializer_list<V> il, A&&... a );
-
-  template<size_t I, class... A>
-    constexpr variant_alternative_t<I, variant<T...>>&
-      emplace( A&&... a );
-  template<size_t I, class V, class... A>
-    constexpr variant_alternative_t<I, variant<T...>>&
-      emplace( std::initializer_list<V> il, A&&... a );
-
-  // value status
-
-  constexpr bool valueless_by_exception() const noexcept;
-  constexpr size_t index() const noexcept;
-
-  // swap
-
-  void swap( variant& r ) noexcept( /*see below*/ );
-
-  // converting constructors (extension)
-
-  template<class... U> variant( variant<U...> const& r )
-    noexcept( /*see below*/ );
-
-  template<class... U> variant( variant<U...>&& r )
-    noexcept( /*see below*/ );
-
-  // subset (extension)
-
-  template<class... U> constexpr variant<U...> subset() & ;
-  template<class... U> constexpr variant<U...> subset() && ;
-  template<class... U> constexpr variant<U...> subset() const& ;
-  template<class... U> constexpr variant<U...> subset() const&& ;
-};
-
-} // namespace variant2
-} // namespace boost
-
-
-
-

In the descriptions that follow, let i be in the range [0, sizeof…​(T)), -and Ti be the i-th type in T…​.

-
-
-
Constructors
-
-
-
constexpr variant() noexcept( std::is_nothrow_default_constructible_v<T0> );
-
-
-
-
    -
  • -

    -
    -
    -
    Effects:
    -
    -

    Constructs a variant holding a value-initialized value of -type T0.

    -
    -
    Ensures:
    -
    -

    index() == 0.

    -
    -
    Throws:
    -
    -

    Any exception thrown by the value-initialization of T0.

    -
    -
    Remarks:
    -
    -

    This function does not participate in overload resolution unless -std::is_default_constructible_v<T0> is true.

    -
    -
    -
    -
  • -
-
-
-
-
constexpr variant( variant const & w )
-  noexcept( mp_all<std::is_nothrow_copy_constructible<T>...>::value );
-
-
-
-
    -
  • -

    -
    -
    -
    Effects:
    -
    -

    Initializes the variant to hold the same alternative and value as -w.

    -
    -
    Throws:
    -
    -

    Any exception thrown by the initialization of the contained value.

    -
    -
    Remarks:
    -
    -

    This function does not participate in overload resolution unless -std::is_copy_constructible_v<Ti> is true for all i.

    -
    -
    -
    -
  • -
-
-
-
-
constexpr variant( variant&& w )
-  noexcept( mp_all<std::is_nothrow_move_constructible<T>...>::value );
-
-
-
-
    -
  • -

    -
    -
    -
    Effects:
    -
    -

    Initializes the variant to hold the same alternative and value as -w.

    -
    -
    Throws:
    -
    -

    Any exception thrown by the move-initialization of the contained -value.

    -
    -
    Remarks:
    -
    -

    This function does not participate in overload resolution unless -std::is_move_constructible_v<Ti> is true for all i.

    -
    -
    -
    -
  • -
-
-
-
-
template<class U> constexpr variant( 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:
    -
    -

    Initializes *this to hold the alternative type Tj and -initializes the contained value from std::forward<U>(u).

    -
    -
    Ensures:
    -
    -

    holds_alternative<Tj>(*this).

    -
    -
    Throws:
    -
    -

    Any exception thrown by the initialization of the contained value.

    -
    -
    Remarks:
    -
    -

    The expression inside noexcept is equivalent to -std::is_nothrow_constructible_v<Tj, U>. This function does not participate in -overload resolution unless

    -
    -
      -
    • -

      sizeof…​(T) is nonzero,

      -
    • -
    • -

      std::is_same_v<std::remove_cvref_t<U>, variant> is false,

      -
    • -
    • -

      std::remove_cvref_t<U> is neither a specialization of in_place_type_t nor a -specialization of in_place_index_t,

      -
    • -
    • -

      std::is_constructible_v<Tj, U> is true, and

      -
    • -
    • -

      the expression FUN(std::forward<U>(u)) is well-formed.

      -
    • -
    -
    -
    -
    -
    -
  • -
-
-
-
-
template<class U, class... A>
-  constexpr explicit variant( in_place_type_t<U>, A&&... a );
-
-
-
-
    -
  • -

    -
    -
    -
    Effects:
    -
    -

    Initializes the contained value of type U with the arguments -std::forward<A>(a)…​.

    -
    -
    Ensures:
    -
    -

    holds_alternative<U>(*this).

    -
    -
    Throws:
    -
    -

    Any exception thrown by the initialization of the contained value.

    -
    -
    Remarks:
    -
    -

    This function does not participate in overload resolution unless -there is exactly one occurrence of U in T…​ and -std::is_constructible_v<U, A…​> is true.

    -
    -
    -
    -
  • -
-
-
-
-
template<class U, class V, class... A>
-  constexpr explicit variant( in_place_type_t<U>, std::initializer_list<V> il,
-    A&&... a );
-
-
-
-
    -
  • -

    -
    -
    -
    Effects:
    -
    -

    Initializes the contained value of type U with the arguments il, -std::forward<A>(a)…​.

    -
    -
    Ensures:
    -
    -

    holds_alternative<U>(*this).

    -
    -
    Throws:
    -
    -

    Any exception thrown by the initialization of the contained value.

    -
    -
    Remarks:
    -
    -

    This function does not participate in overload resolution unless -there is exactly one occurrence of U in T…​ and -std::is_constructible_v<U, initializer_list<V>&, A…​> is true.

    -
    -
    -
    -
  • -
-
-
-
-
template<size_t I, class... A>
-  constexpr explicit variant( in_place_index_t<I>, A&&... a );
-
-
-
-
    -
  • -

    -
    -
    -
    Effects:
    -
    -

    Initializes the contained value of type TI with the arguments -std::forward<A>(a)…​.

    -
    -
    Ensures:
    -
    -

    index() == I.

    -
    -
    Throws:
    -
    -

    Any exception thrown by the initialization of the contained value.

    -
    -
    Remarks:
    -
    -

    This function does not participate in overload resolution unless -I < sizeof…​(T) and std::is_constructible_v<TI, A…​> is true.

    -
    -
    -
    -
  • -
-
-
-
-
template<size_t I, class V, class... A>
-  constexpr explicit variant( in_place_index_t<I>, std::initializer_list<V> il,
-    A&&... a );
-
-
-
-
    -
  • -

    -
    -
    -
    Effects:
    -
    -

    Initializes the contained value of type TI with the arguments -il, std::forward<A>(a)…​.

    -
    -
    Ensures:
    -
    -

    index() == I.

    -
    -
    Throws:
    -
    -

    Any exception thrown by the initialization of the contained value.

    -
    -
    Remarks:
    -
    -

    This function does not participate in overload resolution unless -I < sizeof…​(T) and -std::is_constructible_v<TI, initializer_list<V>&, A…​> is true.

    -
    -
    -
    -
  • -
-
-
-
-
Destructor
-
-
-
~variant();
-
-
-
-
    -
  • -

    -
    -
    -
    Effects:
    -
    -

    Destroys the currently contained value.

    -
    -
    -
    -
  • -
-
-
-
-
Assignment
-
-
-
constexpr variant& operator=( const variant& r )
-  noexcept( mp_all<std::is_nothrow_copy_constructible<T>...>::value );
-
-
-
-
    -
  • -

    -
    -

    Let j be r.index().

    -
    -
    -
    -
    Effects:
    -
    -

    emplace<j>(get<j>(r)).

    -
    -
    Returns:
    -
    -

    *this.

    -
    -
    Ensures:
    -
    -

    index() == r.index().

    -
    -
    Remarks:
    -
    -

    This operator does not participate in overload resolution unless -std::is_copy_constructible_v<Ti> && std::is_copy_assignable_v<Ti> is -true for all i.

    -
    -
    -
    -
  • -
-
-
-
-
constexpr variant& operator=( variant&& r )
-  noexcept( mp_all<std::is_nothrow_move_constructible<T>...>::value );
-
-
-
-
    -
  • -

    -
    -

    Let j be r.index().

    -
    -
    -
    -
    Effects:
    -
    -

    emplace<j>(get<j>(std::move(r))).

    -
    -
    Returns:
    -
    -

    *this.

    -
    -
    Ensures:
    -
    -

    index() == r.index().

    -
    -
    Remarks:
    -
    -

    This operator does not participate in overload resolution unless -std::is_move_constructible_v<Ti> && std::is_move_assignable_v<Ti> is -true for all i.

    -
    -
    -
    -
  • -
-
-
-
-
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:
    -
    -

    emplace<j>(std::forward<U>(u)).

    -
    -
    Returns:
    -
    -

    *this.

    -
    -
    Ensures:
    -
    -

    index() == j.

    -
    -
    Remarks:
    -
    -

    The expression inside noexcept is std::is_nothrow_constructible_v<Tj, U&&>. -This operator does not participate in overload resolution unless

    -
    -
      -
    • -

      std::is_same_v<std::remove_cvref_t<T>, variant> is false,

      -
    • -
    • -

      std::is_constructible_v<Tj, U&&> && std::is_assignable_v<Tj&, U&&> is -true, and

      -
    • -
    • -

      the expression FUN(std::forward<U>(u)) (with FUN being the -above-mentioned set of imaginary functions) is well-formed.

      -
    • -
    -
    -
    -
    -
    -
  • -
-
-
-
-
Modifiers
-
-
-
template<class U, class... A>
-  constexpr U& emplace( A&&... a );
-
-
-
-
    -
  • -

    -
    -

    Let I be the zero-based index of U in T…​.

    -
    -
    -
    -
    Effects:
    -
    -

    Equivalent to: return emplace<I>(std::forward<A>(a)…​);

    -
    -
    Remarks:
    -
    -

    This function shall not participate in overload resolution unless -std::is_constructible_v<U, A&&…​> is true and U occurs exactly once -in T…​.

    -
    -
    -
    -
  • -
-
-
-
-
template<class U, class V, class... A>
-  constexpr U& emplace( std::initializer_list<V> il, A&&... a );
-
-
-
-
    -
  • -

    -
    -

    Let I be the zero-based index of U in T…​.

    -
    -
    -
    -
    Effects:
    -
    -

    Equivalent to: return emplace<I>(il, std::forward<A>(a)…​);

    -
    -
    Remarks:
    -
    -

    This function shall not participate in overload resolution unless -std::is_constructible_v<U, std::initializer_list<V>&, A&&…​> is true -and U occurs exactly once in T…​.

    -
    -
    -
    -
  • -
-
-
-
-
template<size_t I, class... A>
-  constexpr variant_alternative_t<I, variant<T...>>&
-    emplace( A&&... a );
-
-
-
-
    -
  • -

    -
    -
    -
    Requires:
    -
    -

    I < sizeof…​(T).

    -
    -
    Effects:
    -
    -

    Destroys the currently contained value, then initializes a new contained -value as if using the expression Ti(std::forward<A>(a)…​).

    -
    -
    Ensures:
    -
    -

    index() == I.

    -
    -
    Returns:
    -
    -

    A reference to the new contained value.

    -
    -
    Throws:
    -
    -

    Nothing unless the initialization of the new contained value throws.

    -
    -
    Exception Safety:
    -
    -

    Strong. On exception, the contained value is unchanged.

    -
    -
    Remarks:
    -
    -

    This function shall not participate in overload resolution unless -std::is_constructible_v<Ti, A&&…​> is true.

    -
    -
    -
    -
  • -
-
-
-
-
template<size_t I, class V, class... A>
-  constexpr variant_alternative_t<I, variant<T...>>&
-    emplace( std::initializer_list<V> il, A&&... a );
-
-
-
-
    -
  • -

    -
    -
    -
    Requires:
    -
    -

    I < sizeof…​(T).

    -
    -
    Effects:
    -
    -

    Destroys the currently contained value, then initializes a new contained -value as if using the expression Ti(il, std::forward<A>(a)…​).

    -
    -
    Ensures:
    -
    -

    index() == I.

    -
    -
    Returns:
    -
    -

    A reference to the new contained value.

    -
    -
    Throws:
    -
    -

    Nothing unless the initialization of the new contained value throws.

    -
    -
    Exception Safety:
    -
    -

    Strong. On exception, the contained value is unchanged.

    -
    -
    Remarks:
    -
    -

    This function shall not participate in overload resolution unless -std::is_constructible_v<Ti, std::initializer_list<V>&, A&&…​> is true.

    -
    -
    -
    -
  • -
-
-
-
-
Value Status
-
-
-
constexpr bool valueless_by_exception() const noexcept;
-
-
-
-
    -
  • -

    -
    -
    -
    Returns:
    -
    -

    false.

    -
    -
    -
    -
    - - - - - -
    -
    Note
    -
    -This function is provided purely for compatibility with std::variant. -
    -
    -
  • -
-
-
-
-
constexpr size_t index() const noexcept;
-
-
-
-
    -
  • -

    -
    -
    -
    Returns:
    -
    -

    The zero-based index of the active alternative.

    -
    -
    -
    -
  • -
-
-
-
-
Swap
-
-
-
void swap( variant& r ) noexcept( mp_all<std::is_nothrow_move_constructible<T>...,
-  is_nothrow_swappable<T>...>::value );
-
-
-
-
    -
  • -

    -
    -
    -
    Effects:
    -
    -
    -
      -
    • -

      If index() == r.index(), calls swap(get<I>(*this), get<I>(r)), -where I is index().

      -
    • -
    • -

      Otherwise, as if -variant tmp(std::move(*this)); *this = std::move(r); r = std::move(tmp);

      -
    • -
    -
    -
    -
    -
    -
  • -
-
-
-
-
Converting Constructors (extension)
-
-
-
template<class... U> variant( variant<U...> const& r )
-  noexcept( mp_all<std::is_nothrow_copy_constructible<U>...>::value );
-
-
-
-
    -
  • -

    -
    -
    -
    Effects:
    -
    -

    Initializes the contained value from the contained value of r.

    -
    -
    Throws:
    -
    -

    Any exception thrown by the initialization of the contained value.

    -
    -
    Remarks:
    -
    -

    This function does not participate in overload resolution unless -all types in U…​ are in T…​ and -std::is_copy_constructible_v<Ui>::value is true for all Ui.

    -
    -
    -
    -
  • -
-
-
-
-
template<class... U> variant( variant<U...>&& r )
-  noexcept( mp_all<std::is_nothrow_move_constructible<U>...>::value );
-
-
-
-
    -
  • -

    -
    -
    -
    Effects:
    -
    -

    Initializes the contained value from the contained value of -std::move(r).

    -
    -
    Throws:
    -
    -

    Any exception thrown by the initialization of the contained value.

    -
    -
    Remarks:
    -
    -

    This function does not participate in overload resolution unless -all types in U…​ are in T…​ and -std::is_move_constructible_v<Ui>::value is true for all Ui.

    -
    -
    -
    -
  • -
-
-
-
-
Subset (extension)
-
-
-
template<class... U> constexpr variant<U...> subset() & ;
-
-
-
-
-
template<class... U> constexpr variant<U...> subset() const& ;
-
-
-
-
    -
  • -

    -
    -
    -
    Returns:
    -
    -

    A variant<U…​> whose contained value is copy-initialized from -the contained value of *this and has the same type.

    -
    -
    Throws:
    -
    -
    -
      -
    • -

      If the active alternative of *this is not among the types in U…​, -bad_variant_access.

      -
    • -
    • -

      Otherwise, any exception thrown by the initialization of the contained value.

      -
    • -
    -
    -
    -
    Remarks:
    -
    -

    This function does not participate in overload resolution unless -all types in U…​ are in T…​ and -std::is_copy_constructible_v<Ui>::value is true for all Ui.

    -
    -
    -
    -
  • -
-
-
-
-
template<class... U> constexpr variant<U...> subset() && ;
-
-
-
-
-
template<class... U> constexpr variant<U...> subset() const&& ;
-
-
-
-
    -
  • -

    -
    -
    -
    Returns:
    -
    -

    A variant<U…​> whose contained value is move-initialized from -the contained value of *this and has the same type.

    -
    -
    Throws:
    -
    -
    -
      -
    • -

      If the active alternative of *this is not among the types in U…​, -bad_variant_access.

      -
    • -
    • -

      Otherwise, any exception thrown by the initialization of the contained value.

      -
    • -
    -
    -
    -
    Remarks:
    -
    -

    This function does not participate in overload resolution unless -all types in U…​ are in T…​ and -std::is_move_constructible_v<Ui>::value is true for all Ui.

    -
    -
    -
    -
  • -
-
-
-
-
-

variant_alternative

-
-
-
template<size_t I, class T> struct variant_alternative<I, T const>;
-
-
-
-
-
template<size_t I, class T> struct variant_alternative<I, T volatile>;
-
-
-
-
-
template<size_t I, class T> struct variant_alternative<I, T const volatile>;
-
-
-
-
-
template<size_t I, class T> struct variant_alternative<I, T&>; // extension
-
-
-
-
-
template<size_t I, class T> struct variant_alternative<I, T&&>; // extension
-
-
-
-
    -
  • -

    -
    -
    -
    -

    If typename variant_alternative<I, T>::type exists and is U,

    -
    -
    -
      -
    • -

      variant_alternative<I, T const>::type is U const;

      -
    • -
    • -

      variant_alternative<I, T volatile>::type is U volatile;

      -
    • -
    • -

      variant_alternative<I, T const volatile>::type is U const volatile.

      -
    • -
    • -

      variant_alternative<I, T&>::type is U&.

      -
    • -
    • -

      variant_alternative<I, T&&>::type is U&&.

      -
    • -
    -
    -
    -

    Otherwise, these structs have no member type.

    -
    -
    -
    -
  • -
-
-
-
-
template<size_t I, class... T>
-  struct variant_alternative<I, variant<T...>>;
-
-
-
-
    -
  • -

    -
    -

    When I < sizeof…​(T), the nested type type is an alias for the I-th -(zero-based) type in T…​. Otherwise, there is no member type.

    -
    -
  • -
-
-
-
-

holds_alternative

-
-
-
template<class U, class... T>
-  constexpr bool holds_alternative(const variant<T...>& v) noexcept;
-
-
-
-
    -
  • -

    -
    -
    -
    Requires:
    -
    -

    The type U occurs exactly once in T…​. Otherwise, the -program is ill-formed.

    -
    -
    Returns:
    -
    -

    true if index() is equal to the zero-based index of U -in T…​.

    -
    -
    -
    -
  • -
-
-
-
-

get

-
-
-
template<size_t I, class... T>
-  constexpr variant_alternative_t<I, variant<T...>>&
-    get(variant<T...>& v);
-
-
-
-
-
template<size_t I, class... T>
-  constexpr variant_alternative_t<I, variant<T...>>&&
-    get(variant<T...>&& v);
-
-
-
-
-
template<size_t I, class... T>
-  constexpr const variant_alternative_t<I, variant<T...>>&
-    get(const variant<T...>& v);
-
-
-
-
-
template<size_t I, class... T>
-  constexpr const variant_alternative_t<I, variant<T...>>&&
-    get(const variant<T...>&& v);
-
-
-
-
    -
  • -

    -
    -
    -
    Effects:
    -
    -

    If v.index() is I, returns a reference to the object stored in -the variant. Otherwise, throws bad_variant_access.

    -
    -
    Remarks:
    -
    -

    These functions do not participate in overload resolution -unless I < sizeof…​(T).

    -
    -
    -
    -
  • -
-
-
-
-
template<class U, class... T>
-  constexpr U& get(variant<T...>& v);
-
-
-
-
-
template<class U, class... T>
-  constexpr U&& get(variant<T...>&& v);
-
-
-
-
-
template<class U, class... T>
-  constexpr const U& get(const variant<T...>& v);
-
-
-
-
-
template<class U, class... T>
-  constexpr const U&& get(const variant<T...>&& v);
-
-
-
-
    -
  • -

    -
    -
    -
    Requires:
    -
    -

    The type U occurs exactly once in T…​. Otherwise, the -program is ill-formed.

    -
    -
    Effects:
    -
    -

    If v holds a value of type U, returns a reference to that value. -Otherwise, throws bad_variant_access.

    -
    -
    -
    -
  • -
-
-
-
-

get_if

-
-
-
template<size_t I, class... T>
-  constexpr add_pointer_t<variant_alternative_t<I, variant<T...>>>
-    get_if(variant<T...>* v) noexcept;
-
-
-
-
-
template<size_t I, class... T>
-  constexpr add_pointer_t<const variant_alternative_t<I, variant<T...>>>
-    get_if(const variant<T...>* v) noexcept;
-
-
-
-
    -
  • -

    -
    -
    -
    Effects:
    -
    -

    A pointer to the value stored in the variant, if -v != nullptr && v->index() == I. Otherwise, nullptr.

    -
    -
    Remarks:
    -
    -

    These functions do not participate in overload resolution -unless I < sizeof…​(T).

    -
    -
    -
    -
  • -
-
-
-
-
template<class U, class... T>
-  constexpr add_pointer_t<U>
-    get_if(variant<T...>* v) noexcept;
-
-
-
-
-
template<class U, class... T>
-  constexpr add_pointer_t<const U>
-    get_if(const variant<T...>* v) noexcept;
-
-
-
-
    -
  • -

    -
    -
    -
    Requires:
    -
    -

    The type U occurs exactly once in T…​. Otherwise, the -program is ill-formed.

    -
    -
    Effects:
    -
    -

    Equivalent to: return get_if<I>(v); with I being -the zero-based index of U in T…​.

    -
    -
    -
    -
  • -
-
-
-
-

Relational Operators

-
-
-
template<class... T>
-  constexpr bool operator==(const variant<T...>& v, const variant<T...>& w);
-
-
-
-
    -
  • -

    -
    -
    -
    Returns:
    -
    -

    v.index() == w.index() && get<I>(v) == get<I>(w), where I -is v.index().

    -
    -
    -
    -
  • -
-
-
-
-
template<class... T>
-  constexpr bool operator!=(const variant<T...>& v, const variant<T...>& w);
-
-
-
-
    -
  • -

    -
    -
    -
    Returns:
    -
    -

    !(v == w).

    -
    -
    -
    -
  • -
-
-
-
-
template<class... T>
-  constexpr bool operator<(const variant<T...>& v, const variant<T...>& w);
-
-
-
-
    -
  • -

    -
    -
    -
    Returns:
    -
    -

    v.index() < w.index() || (v.index() == w.index() && get<I>(v) < get<I>(w)), -where I is v.index().

    -
    -
    -
    -
  • -
-
-
-
-
template<class... T>
-  constexpr bool operator>(const variant<T...>& v, const variant<T...>& w);
-
-
-
-
    -
  • -

    -
    -
    -
    Returns:
    -
    -

    w < v.

    -
    -
    -
    -
  • -
-
-
-
-
template<class... T>
-  constexpr bool operator<=(const variant<T...>& v, const variant<T...>& w);
-
-
-
-
    -
  • -

    -
    -
    -
    Returns:
    -
    -

    v.index() < w.index() || (v.index() == w.index() && get<I>(v) <= get<I>(w)), -where I is v.index().

    -
    -
    -
    -
  • -
-
-
-
-
template<class... T>
-  constexpr bool operator>=(const variant<T...>& v, const variant<T...>& w);
-
-
-
-
    -
  • -

    -
    -
    -
    Returns:
    -
    -

    w <= v.

    -
    -
    -
    -
  • -
-
-
-
-

visit

-
-
-
template<class F, class... V>
-  constexpr /*see below*/ visit(F&& f, V&&... v);
-
-
-
-
    -
  • -

    -
    -
    -
    Returns:
    -
    -

    std::forward<F>(f)(get<I>(std::forward<V>(v))…​), where -I…​ is v.index()…​.

    -
    -
    -
    -
  • -
-
-
-
-

swap

-
-
-
template<class... T>
-  void swap(variant<T...>& v, variant<T...>& w) noexcept( /*see below*/ );
-
-
-
-
    -
  • -

    -
    -
    -
    Effects:
    -
    -

    Equivalent to v.swap(w).

    -
    -
    -
    -
  • -
-
-
-
-

bad_variant_access

-
-
-
class bad_variant_access: public std::exception
-{
-public:
-
-    bad_variant_access() noexcept = default;
-
-    char const * what() const noexcept
-    {
-        return "bad_variant_access";
-    }
-};
-
-
-
-
-
-
-
- -
-
-

This documentation is copyright 2018, 2019 Peter Dimov and is distributed under -the Boost Software License, Version 1.0.

-
-
-
-
- - - - \ No newline at end of file