Reference

namespace eggs { namespace variants {
  // variant for object types
  template <class ...Ts> class variant;

  // In-place construction
  struct in_place_tag {};
  template <std::size_t I>
  using in_place_index_t = in_place_tag(&)(unspecified<I>);
  template <class T>
  using in_place_type_t = in_place_tag(&)(unspecified<T>);
  template <std::size_t I>
  in_place_tag in_place(unspecified<I>);
  template <class T>
  in_place_tag in_place(unspecified<T>);

  // Class bad_variant_access
  class bad_variant_access;

  // Class template variant
  template <class ...Ts>
  class variant {
  public:
    static constexpr std::size_t npos = std::size_t(-1);

    // Constructors
    constexpr variant() noexcept;
    constexpr variant(variant const&);
    constexpr variant(variant&&) noexcept(see below);
    template <class U>
    constexpr variant(U&&);
    template <std::size_t I, class ...Args>
    constexpr explicit variant(in_place_index_t<I>, Args&&...);
    template <std::size_t I, class U, class ...Args>
    constexpr explicit variant(in_place_index_t<I>, std::initializer_list<U>, Args&&...);
    template <class T, class ...Args>
    constexpr explicit variant(in_place_type_t<T>, Args&&...);
    template <class T, class U, class ...Args>
    constexpr explicit variant(in_place_type_t<T>, std::initializer_list<U>, Args&&...);

    // Destructor
    ~variant();

    // Assignment
    constexpr variant& operator=(variant const&);
    constexpr variant& operator=(variant&&) noexcept(see below);
    template <class U>
    constexpr variant& operator=(U&&);
    template <std::size_t I, class ...Args>
    constexpr T& emplace(Args&&...);
    template <std::size_t I, class U, class ...Args>
    constexpr T& emplace(std::initializer_list<U>, Args&&...);
    template <class T, class ...Args>
    constexpr T& emplace(Args&&...);
    template <class T, class U, class ...Args>
    constexpr T& emplace(std::initializer_list<U>, Args&&...);

    // Swap
    constexpr void swap(variant&) noexcept(see below);

    // Observers
    constexpr explicit operator bool() const noexcept;
    constexpr std::size_t which() const noexcept;
    constexpr std::type_info const& target_type() const noexcept;
    constexpr void* target() noexcept;
    constexpr void const* target() const noexcept;
    template <class T>
    constexpr T* target() noexcept;
    template <class T>
    constexpr T const* target() const noexcept;
  };

  // Class bad_variant_access
  class bad_variant_access : public std::exception {
  public:
    bad_variant_access() noexcept;
    char const* what() const noexcept override;
  };

  // Helper classes
  template <class T>
  struct variant_size;
  template <class ...Ts>
  struct variant_size<variant<Ts...>>;
  template <class T>
  struct variant_size<T const>;
  template <class T>
  constexpr std::size_t variant_size_v = variant_size<T>::value;

  template <std::size_t I, class T>
  struct variant_element; // undefined
  template <std::size_t I, class ...Ts>
  struct variant_element<I, variant<Ts...>>;
  template <std::size_t I, class T>
  struct variant_element<I, T const>;
  template <std::size_t I, class T>
  using variant_element_t = class variant_element<I, T>::type;

  // Element access
  template <std::size_t I, class ...Ts>
  constexpr variant_element_t<I, variant<Ts...>>& get(variant<Ts...>&);
  template <std::size_t I, class ...Ts>
  constexpr variant_element_t<I, variant<Ts...>> const& get(variant<Ts...> const&);
  template <std::size_t I, class ...Ts>
  constexpr variant_element_t<I, variant<Ts...>>&& get(variant<Ts...>&&);
  template <std::size_t I, class ...Ts>
  constexpr variant_element_t<I, variant<Ts...>> const&& get(variant<Ts...> const&&);

  template <class T, class ...Ts>
  constexpr T& get(variant<Ts...>&);
  template <class T, class ...Ts>
  constexpr T const& get(variant<Ts...> const&);
  template <class T, class ...Ts>
  constexpr T&& get(variant<Ts...>&&);
  template <class T, class ...Ts>
  constexpr T const&& get(variant<Ts...> const&&);

  template <std::size_t I, class ...Ts>
  constexpr variant_element_t<I, variant<Ts...>>* get_if(variant<Ts...>*) noexcept;
  template <std::size_t I, class ...Ts>
  constexpr variant_element_t<I, variant<Ts...>> const* get_if(variant<Ts...> const*) noexcept;
  template <class T, class ...Ts>
  constexpr T* get_if(variant<Ts...>*) noexcept;
  template <class T, class ...Ts>
  constexpr T const* get_if(variant<Ts...> const*) noexcept;

  // Relational operators
  template <class ...Ts>
  constexpr bool operator==(variant<Ts...> const&, variant<Ts...> const&);
  template <class ...Ts>
  constexpr bool operator!=(variant<Ts...> const&, variant<Ts...> const&);
  template <class ...Ts>
  constexpr bool operator<(variant<Ts...> const&, variant<Ts...> const&);
  template <class ...Ts>
  constexpr bool operator>(variant<Ts...> const&, variant<Ts...> const&);
  template <class ...Ts>
  constexpr bool operator<=(variant<Ts...> const&, variant<Ts...> const&);
  template <class ...Ts>
  constexpr bool operator>=(variant<Ts...> const&, variant<Ts...> const&);

  // Comparison with Ts
  template <class ...Ts, class U>
  constexpr bool operator==(variant<Ts...> const&, U const&);
  template <class U, class ...Ts>
  constexpr bool operator==(U const&, variant<Ts...> const&);
  template <class ...Ts, class U>
  constexpr bool operator!=(variant<Ts...> const&, U const&);
  template <class U, class ...Ts>
  constexpr bool operator!=(U const&, variant<Ts...> const&);
  template <class ...Ts, class U>
  constexpr bool operator<(variant<Ts...> const&, U const&);
  template <class U, class ...Ts>
  constexpr bool operator<(U const&, variant<Ts...> const&);
  template <class ...Ts, class U>
  constexpr bool operator>(variant<Ts...> const&, U const&);
  template <class U, class ...Ts>
  constexpr bool operator>(U const&, variant<Ts...> const&);
  template <class ...Ts, class U>
  constexpr bool operator<=(variant<Ts...> const&, U const&);
  template <class U, class ...Ts>
  constexpr bool operator<=(U const&, variant<Ts...> const&);
  template <class ...Ts, class U>
  constexpr bool operator>=(variant<Ts...> const&, U const&);
  template <class U, class ...Ts>
  constexpr bool operator>=(U const&, variant<Ts...> const&);

  // Calling a function with variants of arguments
  template <class R, class F, class ...Vs>
  constexpr R apply(F&&, Vs&&...);
  template <class F, class ...Vs>
  constexpr see below apply(F&&, Vs&&...);

  // Specialized algorithms
  template <class ...Ts>
  constexpr void swap(variant<Ts...>&, variant<Ts...>&) noexcept(see below);
}}
// Hash support
namespace std {
  template <class ...Ts>
  struct hash<::eggs::variants::variant<Ts...>>;
}
namespace eggs {
  using variants::variant;
}

Class template variant

template <class ...Ts>
class variant {
public:
  static constexpr std::size_t npos = std::size_t(-1);

  // Constructors
  constexpr variant() noexcept;
  constexpr variant(variant const&);
  constexpr variant(variant&&) noexcept(see below);
  template <class U>
  constexpr variant(U&&);
  template <std::size_t I, class ...Args>
  constexpr explicit variant(in_place_index_t<I>, Args&&...);
  template <std::size_t I, class U, class ...Args>
  constexpr explicit variant(in_place_index_t<I>, std::initializer_list<U>, Args&&...);
  template <class T, class ...Args>
  constexpr explicit variant(in_place_type_t<T>, Args&&...);
  template <class T, class U, class ...Args>
  constexpr explicit variant(in_place_type_t<T>, std::initializer_list<U>, Args&&...);

  // Destructor
  ~variant();

  // Assignment
  constexpr variant& operator=(variant const&);
  constexpr variant& operator=(variant&&) noexcept(see below);
  template <class U>
  constexpr variant& operator=(U&&);
  template <std::size_t I, class ...Args>
  constexpr T& emplace(Args&&...);
  template <std::size_t I, class U, class ...Args>
  constexpr T& emplace(std::initializer_list<U>, Args&&...);
  template <class T, class ...Args>
  constexpr T& emplace(Args&&...);
  template <class T, class U, class ...Args>
  constexpr T& emplace(std::initializer_list<U>, Args&&...);

  // Swap
  constexpr void swap(variant&) noexcept(see below);

  // Observers
  constexpr explicit operator bool() const noexcept;
  constexpr std::size_t which() const noexcept;
  constexpr std::type_info const& target_type() const noexcept;
  constexpr void* target() noexcept;
  constexpr void const* target() const noexcept;
  template <class T>
  constexpr T* target() noexcept;
  template <class T>
  constexpr T const* target() const noexcept;
};

In a variant, at most one of the members can be active at any time, that is, the value of at most one of the members can be stored in a variant at any time. Implementations are not permitted to use additional storage, such as dynamic memory, to allocate its contained value. The contained value shall be allocated in a region of the variant<Ts...> storage suitably aligned for the types Ts....

All T in Ts... shall be object types and shall satisfy the requirements of Destructible.

Constructors

constexpr variant() noexcept;
  • Postconditions: *this does not have an active member.
  • Remarks: No member is initialized. For every object types Ts... this constructor shall be a constexpr constructor.
constexpr variant(variant const& rhs);
  • Effects: If rhs has an active member of type T, initializes the active member as if direct-non-list-initializing an object of type T with the expression *rhs.target<T>(); otherwise, no member is initialized.
  • Postconditions: rhs.which() == this->which().
  • Throws: Any exception thrown by the selected constructor of T.
  • Remarks: This constructor shall be defined as deleted unless std::is_copy_constructible_v<T> is true for all T in Ts.... If std::is_trivially_copyable_v<T> is true for all T in Ts..., then this copy constructor shall be a trivial constexpr constructor.
constexpr variant(variant&& rhs) noexcept(see below);
  • Effects: If rhs has an active member of type T, initializes the active member as if direct-non-list-initializing an object of type T with the expression std::move(*rhs.target<T>()); otherwise, no member is initialized. bool(rhs) is unchanged.
  • Postconditions: rhs.which() == this->which().
  • Throws: Any exception thrown by the selected constructor of T.
  • Remarks: The expression inside noexcept is equivalent to the logical AND of std::is_nothrow_move_constructible_v<Ts>.... This constructor shall not participate in overload resolution unless std::is_move_constructible_v<T> is true for all T in Ts.... If std::is_trivially_copyable_v<T> is true for all T in Ts..., then this move constructor shall be a trivial constexpr constructor.
template <class U>
constexpr variant(U&& v);
  • Let T be one of the types in Ts... for which std::forward<U>(u) is unambiguously convertible to by overload resolution rules.
  • Effects: Initializes the active member as if direct-non-list-initializing an object of type T with the expression std::forward<U>(v).
  • Postconditions: *this has an active member.
  • Throws: Any exception thrown by the selected constructor of T.
  • Remarks: This constructor shall not participate in overload resolution unless std::is_same_v<std::decay_t<U>, variant> is false, there is a type T in Ts... for which std::forward<U>(u) is unambiguously convertible to by overload resolution rules, and std::is_constructible_v<T, U> is true. If T's selected constructor is a constexpr constructor, this constructor shall be a constexpr constructor.
template <std::size_t I, class ...Args>
constexpr explicit variant(in_place_index_t<I>, Args&&... args);
  • Let T be the Ith element in Ts..., where indexing is zero-based.
  • Effects: Initializes the active member as if direct-non-list-initializing an object of type T with the arguments std::forward<Args>(args)....
  • Postconditions: *this has an active member of type T.
  • Throws: Any exception thrown by the selected constructor of T.
  • Remarks: This constructor shall not participate in overload resolution unless I < sizeof...(Ts), and std::is_constructible_v<T, Args...> is true. If T's selected constructor is a constexpr constructor, this constructor shall be a constexpr constructor.
template <std::size_t I, class U, class ...Args>
constexpr explicit variant(in_place_index_t<I>, std::initializer_list<U> il, Args&&... args);
  • Let T be the Ith element in Ts..., where indexing is zero-based.
  • Effects: Initializes the active member as if direct-non-list-initializing an object of type T with the arguments il, std::forward<Args>(args)....
  • Postconditions: *this has an active member of type T.
  • Throws: Any exception thrown by the selected constructor of T.
  • Remarks: This constructor shall not participate in overload resolution unless I < sizeof...(Ts), and std::is_constructible_v<T, std::initializer_list<U>&, Args...> is true. If T's selected constructor is a constexpr constructor, this constructor shall be a constexpr constructor.
template <class T, class ...Args>
constexpr explicit variant(in_place_type_t<T>, Args&&... args);
  • Effects: Equivalent to variant(in_place<I>, std::forward<Args>(args)...) where I is the zero-based index of T in Ts....
  • Remarks: This constructor shall not participate in overload resolution unless there is exactly one occurrence of T in Ts..., and std::is_constructible_v<T, Args...> is true. If T's selected constructor is a constexpr constructor, this constructor shall be a constexpr constructor.
template <class T, class U, class ...Args>
constexpr explicit variant(in_place_type_t<T>, std::initializer_list<U> il, Args&&... args);
  • Effects: Equivalent to variant(in_place<I>, il, std::forward<Args>(args)...) where I is the zero-based index of T in Ts....
  • Remarks: This constructor shall not participate in overload resolution unless there is exactly one occurrence of T in Ts..., and std::is_constructible_v<T, std::initializer_list<U>&, Args...> is true. If T's selected constructor is a constexpr constructor, this constructor shall be a constexpr constructor.

Destructor

~variant();
  • Effects: If *this has an active member of type T, destroys the active member as if by calling target<T>()->~T().
  • Remarks: If std::is_trivially_destructible_v<T> is true for all T in Ts..., then this destructor shall be trivial.

Assignment

constexpr variant& operator=(variant const& rhs);
  • Effects:
    • If both *this and rhs have an active member of type T, assigns to the active member the expression *rhs.target<T>();
    • otherwise, if *this has an active member of type U, destroys the active member by calling target<U>()->~U(). Then, if rhs has an active member of type T, initializes the active member as if direct-non-list-initializing an object of type T with the expression *rhs.target<T>().
  • Returns: *this.
  • Postconditions: rhs.which() == this->which().
  • Remarks: If an exception is thrown during the call to T's copy assignment, the state of the active member is as defined by the exception safety guarantee of T's copy assignment. If an exception is thrown during the call to T's copy constructor, *this has no active member, and the previous active member (if any) has been destroyed. This function shall be defined as deleted unless std::is_copy_assignable_v<T> && std::is_copy_constructible_v<T> is true for all T in Ts.... If std::is_trivially_copyable_v<T> is true for all T in Ts..., then this copy assignment operator shall be a trivial constexpr assignment operator.
constexpr variant& operator=(variant&& rhs) noexcept(see below);
  • Effects:
    • If both *this and rhs have an active member of type T, assigns to the active member the expression std::move(*rhs.target<T>());
    • otherwise, if *this has an active member of type U, destroys the active member by calling target<U>()->~U(). Then, if rhs has an active member of type T, initializes the active member as if direct-non-list-initializing an object of type T with the expression std::move(*rhs.target<Tn>()).
  • bool(rhs) is unchanged.
  • Returns: *this.
  • Postconditions: rhs.which() == this->which().
  • Remarks: If an exception is thrown during the call to T's move assignment, the state of both active members is determined by the exception safety guarantee of T's move assignment. If an exception is thrown during the call to T's move constructor, *this has no active member, the previous active member (if any) has been destroyed, and the state of the active member of rhs is determined by the exception safety guarantee of T's move constructor. The expression inside noexcept is equivalent to the logical AND of std::is_nothrow_move_assignable_v<Ts>... and std::is_nothrow_move_constructible_v<Ts>.... This function shall not participate in overload resolution unless std::is_move_assignable_v<T> && std::is_move_constructible_v<T> is true for all T in Ts.... If std::is_trivially_copyable_v<T> is true for all T in Ts..., then this move assignment operator shall be a trivial constexpr assignment operator.
template <class U>
constexpr variant& operator=(U&& v);
  • Let T be one of the types in Ts... for which std::forward<U>(u) is unambiguously convertible to by overload resolution rules.
  • Effects:
    • If *this has an active member of type T, assigns to the active member the expression std::forward<U>(v);
    • otherwise, calls *this = {}. Then, initializes the active member as if direct-non-list-initializing an object of type T with the expression std::forward<U>(v).
  • Returns: *this.
  • Postconditions: *this has an active member.
  • Remarks: If an exception is thrown during the call to T's assignment, the state of the active member is as defined by the exception safety guarantee of T's assignment. If an exception is thrown during the call to T's constructor, *this has no active member, and the previous active member (if any) has been destroyed. This function shall not participate in overload resolution unless std::is_same_v<std::decay_t<U>, variant> is false, there is a type T in Ts... for which std::forward<U>(u) is unambiguously convertible to by overload resolution rules, and std::is_constructible_v<T, U> is true. This function shall be defined as deleted unless std::is_assignable_v<T&, U> is true. If std::is_trivially_copyable_v<T> is true for all T in Ts... and T's selected constructor is a constexpr constructor, then this function shall be a constexpr function.
template <std::size_t I, class ...Args>
constexpr T& emplace(Args&&... args);
  • Let T be the Ith element in Ts..., where indexing is zero-based.
  • Requires: I < sizeof...(Ts).
  • Effects: Calls *this = {}. Then, initializes the active member as if direct-non-list-initializing an object of type T with the arguments std::forward<Args>(args)....
  • Postconditions: *this has an active member of type T.
  • Returns: A reference to the new contained value.
  • Throws: Any exception thrown by the selected constructor of T.
  • Remarks: If an exception is thrown during the call to T's constructor, *this has no active member, and the previous active member (if any) has been destroyed. This function shall not participate in overload resolution unless std::is_constructible_v<T, Args...> is true. If std::is_trivially_copyable_v<T> && std::is_copy_assignable_v<T> is true for all T in Ts... and T's selected constructor is a constexpr constructor, then this function shall be a constexpr function.
template <std::size_t I, class U, class ...Args>
constexpr T& emplace(std::initializer_list<U> il, Args&&... args);
  • Let T be the Ith element in Ts..., where indexing is zero-based.
  • Requires: I < sizeof...(Ts).
  • Effects: Calls *this = {}. Then, initializes the active member as if direct-non-list-initializing an object of type T with the arguments il, std::forward<Args>(args)....
  • Postconditions: *this has an active member of type T.
  • Returns: A reference to the new contained value.
  • Throws: Any exception thrown by the selected constructor of T.
  • Remarks: If an exception is thrown during the call to T's constructor, *this has no active member, and the previous active member (if any) has been destroyed. This function shall not participate in overload resolution unless std::is_constructible_v<T, std::initializer_list<U>&, Args...> is true. If std::is_trivially_copyable_v<T> && std::is_copy_assignable_v<T> is true for all T in Ts... and T's selected constructor is a constexpr constructor, then this function shall be a constexpr function.
template <class T, class ...Args>
constexpr T& emplace(Args&&... args);
  • Requires: T shall occur exactly once in Ts....
  • Effects: Equivalent to emplace<I>(std::forward<Args>(args)...) where I is the zero-based index of T in Ts....
  • Remarks: This function shall not participate in overload resolution unless std::is_constructible_v<T, Args...> is true. If std::is_trivially_copyable_v<T> && std::is_copy_assignable_v<T> is true for all T in Ts... and T's selected constructor is a constexpr constructor, then this function shall be a constexpr function.
template <class T, class U, class ...Args>
constexpr T& emplace(std::initializer_list<U> il, Args&&... args);
  • Requires: T shall occur exactly once in Ts....
  • Effects: Equivalent to emplace<I>(il, std::forward<Args>(args)...) where I is the zero-based index of T in Ts....
  • Remarks: This function shall not participate in overload resolution unless std::is_constructible_v<T, std::initializer_list<U>&, Args...> is true. If std::is_trivially_copyable_v<T> && std::is_copy_assignable_v<T> is true for all T in Ts... and T's selected constructor is a constexpr constructor, then this function shall be a constexpr function.

Swap

constexpr void swap(variant& rhs) noexcept(see below);
  • Requires: Lvalues of T shall be swappable and std::is_move_constructible_v<T> is true for all T in Ts....
  • Effects:
    • If both *this and rhs have an active member of type T, calls swap(*this->target<T>(), *rhs.target<T>());
    • otherwise, calls std::swap(*this, rhs).
  • Remarks: If an exception is thrown during the call to function swap the state of the active members of type T is determined by the exception safety guarantee of swap for lvalues of T. If an exception is thrown during the call to a move constructor, the state of *this and rhs is unspecified. The expression inside noexcept is equivalent to the logical AND of std::is_nothrow_move_constructible_v<T> && std::is_nothrow_swappable_v<T> for all T in Ts.... If std::is_trivially_copyable_v<T> && std::is_copy_assignable_v<T> is true for all T in Ts..., then this function shall be a constexpr function.

Observers

constexpr explicit operator bool() const noexcept;
  • Returns: true if and only if *this has an active member.
  • Remarks: This function shall be a constexpr function.
constexpr std::size_t which() const noexcept;
  • Returns: The zero-based index of the active member if *this has one. Otherwise, returns npos.
  • Remarks: This function shall be a constexpr function.
constexpr std::type_info const& target_type() const noexcept;
  • Returns: If *this has an active member of type T, typeid(T); otherwise typeid(void).
  • Remarks: This function shall be a constexpr function.
constexpr void* target() noexcept;
  • Returns: If *this has an active member, a pointer to the active member; otherwise a null pointer.
  • Remarks: This function shall be a constexpr function.
constexpr void const* target() const noexcept;
  • Returns: If *this has an active member, a pointer to the active member; otherwise a null pointer.
  • Remarks: This function shall be a constexpr function.
template <class T>
constexpr T* target() noexcept;
  • Returns: If *this has an active member of type T, a pointer to the active member; otherwise a null pointer.
  • Remarks: This function shall be a constexpr function.
template <class T>
constexpr T const* target() const noexcept;
  • Returns: If *this has an active member of type T, a pointer to the active member; otherwise a null pointer.
  • Remarks: This function shall be a constexpr function.

In-place construction

struct in_place_tag {};
template <std::size_t I>
using in_place_index_t = in_place_tag(&)(unspecified<I>);
template <class T>
using in_place_type_t = in_place_tag(&)(unspecified<T>);
template <std::size_t I>
in_place_tag in_place(unspecified<I>);
template <class T>
in_place_tag in_place(unspecified<T>);

The struct in_place_tag is used as a unique type to disambiguate constructor and function overloading. Specifically, variant<Ts...> has a constructor with in_place_type_t<T> as the first parameter, followed by a parameter pack; this indicates that T should be constructed in-place (as if by a call to a placement new expression) with the forwarded pack expansion as arguments for the initialization of T.

Class bad_variant_access

class bad_variant_access : public std::exception {
public:
  bad_variant_access() noexcept;
  char const* what() const noexcept override;
};

Objects of type bad_variant_access are thrown to report attempts to access an inactive member of a variant object.

bad_variant_access() noexcept;
  • Effects: Constructs a bad_variant_access object.
char const* what() const noexcept override;
  • Returns: An implementation-defined NTBS.

Variant helper classes

template <class T>
struct variant_size;
  • Remarks: All specializations of variant_size<T> shall meet the UnaryTypeTrait requirements with a BaseCharacteristic of std::integral_constant<std::size_t, N> for some N if T is a variant-like type; otherwise it shall be empty.
template <class ...Ts>
struct variant_size<variant<Ts...>>;
  • Remarks: Has a BaseCharacteristic of std::integral_constant<std::size_t, sizeof...(Ts)>.
template <class T>
struct variant_size<T const>;
  • Remarks: Let VS denote variant_size<T> of the cv-unqualified type T. Has a BaseCharacteristic of std::integral_constant<std::size_t, VS::value> if T is a variant-like type; otherwise it is empty.
template <std::size_t I, class T>
struct variant_element;
  • Remarks: All specializations of variant_element<I, T> shall meet the TransformationTrait requirements with a member typedef type that names the Ith member of T, where indexing is zero-based.
template <std::size_t I, class ...Ts>
struct variant_element<I, variant<Ts...>>;
  • Requires: I < sizeof...(Ts). Otherwise, the program is ill-formed.
  • Remarks: The member typedef type shall name the type of the Ith element of Ts..., where indexing is zero-based.
template <std::size_t I, class T>
struct variant_element<I, T const>;
  • Remarks: Let VE denote variant_element<I, T> of the cv-unqualified type T. The member typedef type names std::add_const_t<typename VE::type>.

Element access

template <std::size_t I, class ...Ts>
constexpr variant_element_t<I, variant<Ts...>>& get(variant<Ts...>& v);
  • Requires: I < sizeof...(Ts). Otherwise, the program is ill-formed.
  • Returns: A reference to the Ith member of v if it is active, where indexing is zero-based.
  • Throws: bad_variant_access if the Ith member of v is not active.
  • Remarks: This function shall be a constexpr function.
template <std::size_t I, class ...Ts>
constexpr variant_element_t<I, variant<Ts...>> const& get(variant<Ts...> const& v);
  • Requires: I < sizeof...(Ts). Otherwise, the program is ill-formed.
  • Returns: A const reference to the Ith member of v if it is active, where indexing is zero-based.
  • Throws: bad_variant_access if the Ith member of v is not active.
  • Remarks: This function shall be a constexpr function.
template <std::size_t I, class ...Ts>
constexpr variant_element_t<I, variant<Ts...>>&& get(variant<Ts...>&& v);
  • Requires: I < sizeof...(Ts). Otherwise, the program is ill-formed.
  • Effects: Equivalent to return std::forward<variant_element_t<I, variant<Ts...>>>(get<I>(v)).
  • Remarks: This function shall be a constexpr function.
template <std::size_t I, class ...Ts>
constexpr variant_element_t<I, variant<Ts...>> const&& get(variant<Ts...> const&& v);
  • Requires: I < sizeof...(Ts). Otherwise, the program is ill-formed.
  • Effects: Equivalent to return std::forward<variant_element_t<I, variant<Ts...>> const>(get<I>(v)).
  • Remarks: This function shall be a constexpr function.
template <class T, class ...Ts>
constexpr T& get(variant<Ts...>& v);
  • Requires: The type T occurs exactly once in Ts.... Otherwise, the program is ill-formed.
  • Returns: A reference to the active member of v if it is of type T.
  • Throws: bad_variant_access if the active member of v is not of type T.
  • Remarks: This function shall be a constexpr function.
template <class T, class ...Ts>
constexpr T const& get(variant<Ts...> const& v);
  • Requires: The type T occurs exactly once in Ts.... Otherwise, the program is ill-formed.
  • Returns: A const reference to the active member of v if it is of type T.
  • Throws: bad_variant_access if the active member of v is not of type T.
  • Remarks: This function shall be a constexpr function.
template <class T, class ...Ts>
constexpr T&& get(variant<Ts...>&& v);
  • Requires: The type T occurs exactly once in Ts.... Otherwise, the program is ill-formed.
  • Effects: Equivalent to return std::forward<T>(get<T>(v)).
  • Remarks: This function shall be a constexpr function.
template <class T, class ...Ts>
constexpr T const&& get(variant<Ts...> const&& v);
  • Requires: The type T occurs exactly once in Ts.... Otherwise, the program is ill-formed.
  • Effects: Equivalent to return std::forward<T const>(get<T>(v)).
  • Remarks: This function shall be a constexpr function.
template <std::size_t I, class ...Ts>
constexpr variant_element_t<I, variant<Ts...>>* get_if(variant<Ts...>* v) noexcept;
  • Requires: I < sizeof...(Ts). Otherwise, the program is ill-formed.
  • Returns: If v != nullptr, a pointer to the Ith member of *v if it is active, where indexing is zero-based; otherwise, nullptr.
  • Remarks: This function shall be a constexpr function.
template <std::size_t I, class ...Ts>
constexpr variant_element_t<I, variant<Ts...>> const* get_if(variant<Ts...> const* v) noexcept;
  • Requires: I < sizeof...(Ts). Otherwise, the program is ill-formed.
  • Returns: If v != nullptr, a const pointer to the Ith member of *v if it is active, where indexing is zero-based; otherwise, nullptr.
  • Remarks: This function shall be a constexpr function.
template <class T, class ...Ts>
constexpr T* get_if(variant<Ts...>* v) noexcept;
  • Requires: The type T occurs exactly once in Ts.... Otherwise, the program is ill-formed.
  • Returns: If v != nullptr, a pointer to the active member of *v if it is of type T; otherwise, nullptr.
  • Remarks: This function shall be a constexpr function.
template <class T, class ...Ts>
constexpr T const* get_if(variant<Ts...> const* v) noexcept;
  • Requires: The type T occurs exactly once in Ts.... Otherwise, the program is ill-formed.
  • Returns: If v != nullptr, a const pointer to the active member of *v if it is of type T; otherwise, nullptr.
  • Remarks: This function shall be a constexpr function.

Relational operators

template <class ...Ts>
constexpr bool operator==(variant<Ts...> const& lhs, variant<Ts...> const& rhs);
  • Requires: The expression *lhs.target<T>() == *rhs.target<T>() shall be convertible to bool for all T in Ts....
  • Returns: If lhs.which() != rhs.which(), false; otherwise, if !bool(lhs), true; otherwise, *lhs.target<T>() == *rhs.target<T>() where T is the type of the active member of both lhs and rhs.
  • Remarks: This function shall not participate in overload resolution unless the expression *lhs.target<T>() == *rhs.target<T>() is well-formed for all T in Ts.... This function shall be a constexpr function unless lhs.which() == rhs.which() and *lhs.target<T>() == *rhs.target<T>() where T is the type of the active member of both lhs and rhs is not a constant expression.
template <class ...Ts>
constexpr bool operator!=(variant<Ts...> const& lhs, variant<Ts...> const& rhs);
  • Requires: The expression *lhs.target<T>() != *rhs.target<T>() shall be convertible to bool for all T in Ts....
  • Returns: If lhs.which() != rhs.which(), true; otherwise, if !bool(lhs), false; otherwise, *lhs.target<T>() != *rhs.target<T>() where T is the type of the active member of both lhs and rhs.
  • Remarks: This function shall not participate in overload resolution unless the expression *lhs.target<T>() != *rhs.target<T>() is well-formed for all T in Ts.... This function shall be a constexpr function unless lhs.which() == rhs.which() and *lhs.target<T>() != *rhs.target<T>() where T is the type of the active member of both lhs and rhs is not a constant expression.
template <class ...Ts>
constexpr bool operator<(variant<Ts...> const& lhs, variant<Ts...> const& rhs);
  • Requires: The expression *lhs.target<T>() < *rhs.target<T>() shall be convertible to bool for all T in Ts....
  • Returns: If !bool(rhs), false; otherwise, if !bool(lhs), true; otherwise, if lhs.which() == rhs.which(), *lhs.target<T>() < *rhs.target<T>() where T is the type of the active member of both lhs and rhs; otherwise, lhs.which() < rhs.which().
  • Remarks: This function shall not participate in overload resolution unless the expression *lhs.target<T>() < *rhs.target<T>() is well-formed for all T in Ts.... This function shall be a constexpr function unless lhs.which() == rhs.which() and *lhs.target<T>() < *rhs.target<T>() where T is the type of the active member of both lhs and rhs is not a constant expression.
template <class ...Ts>
constexpr bool operator>(variant<Ts...> const& lhs, variant<Ts...> const& rhs);
  • Requires: The expression *lhs.target<T>() > *rhs.target<T>() shall be convertible to bool for all T in Ts....
  • Returns: If !bool(lhs), false; otherwise, if !bool(rhs), true; otherwise, if lhs.which() == rhs.which(), *lhs.target<T>() > *rhs.target<T>() where T is the type of the active member of both lhs and rhs; otherwise, lhs.which() > rhs.which().
  • Remarks: This function shall not participate in overload resolution unless the expression *lhs.target<T>() > *rhs.target<T>() is well-formed for all T in Ts.... This function shall be a constexpr function unless lhs.which() == rhs.which() and *lhs.target<T>() > *rhs.target<T>() where T is the type of the active member of both lhs and rhs is not a constant expression.
template <class ...Ts>
constexpr bool operator<=(variant<Ts...> const& lhs, variant<Ts...> const& rhs);
  • Requires: The expression *lhs.target<T>() <= *rhs.target<T>() shall be convertible to bool for all T in Ts....
  • Returns: If !bool(lhs), true; otherwise, if !bool(rhs), false; otherwise, if lhs.which() == rhs.which(), *lhs.target<T>() <= *rhs.target<T>() where T is the type of the active member of both lhs and rhs; otherwise, lhs.which() < rhs.which().
  • Remarks: This function shall not participate in overload resolution unless the expression *lhs.target<T>() <= *rhs.target<T>() is well-formed for all T in Ts.... This function shall be a constexpr function unless lhs.which() == rhs.which() and *lhs.target<T>() <= *rhs.target<T>() where T is the type of the active member of both lhs and rhs is not a constant expression.
template <class ...Ts>
constexpr bool operator>=(variant<Ts...> const& lhs, variant<Ts...> const& rhs);
  • Requires: The expression *lhs.target<T>() >= *rhs.target<T>() shall be convertible to bool for all T in Ts....
  • Returns: If !bool(rhs), true; otherwise, if !bool(lhs), false; otherwise, if lhs.which() == rhs.which(), *lhs.target<T>() >= *rhs.target<T>() where T is the type of the active member of both lhs and rhs; otherwise, lhs.which() > rhs.which().
  • Remarks: This function shall not participate in overload resolution unless the expression *lhs.target<T>() >= *rhs.target<T>() is well-formed for all T in Ts.... This function shall be a constexpr function unless lhs.which() == rhs.which() and *lhs.target<T>() >= *rhs.target<T>() where T is the type of the active member of both lhs and rhs is not a constant expression.

Comparison with Ts

template <class ...Ts, class U>
constexpr bool operator==(variant<Ts...> const& lhs, U const& rhs);
  • Let T be one of the types in Ts... for which rhs is unambiguously convertible to by overload resolution rules.
  • Requires: The expression *lhs.target<T>() == rhs shall be convertible to bool.
  • Returns: If lhs has an active member of type T, *lhs.target<T>() == rhs; otherwise, false.
  • Remarks: This function shall not participate in overload resolution unless there is a type T in Ts... for which rhs is unambiguously convertible to by overload resolution rules, and the expression *lhs.target<T>() == rhs is well-formed. This function shall be a constexpr function unless lhs has an active member of type T and *lhs.target<T>() == rhs is not a constant expression.
template <class U, class ...Ts>
constexpr bool operator==(U const& lhs, variant<Ts...> const& rhs);
  • Let T be one of the types in Ts... for which lhs is unambiguously convertible to by overload resolution rules.
  • Requires: The expression lhs == *rhs.target<T>() shall be convertible to bool.
  • Returns: If rhs has an active member of type T, lhs == *rhs.target<T>(); otherwise, false.
  • Remarks: This function shall not participate in overload resolution unless there is a type T in Ts... for which lhs is unambiguously convertible to by overload resolution rules, and the expression lhs == *rhs.target<T>() is well-formed. This function shall be a constexpr function unless rhs has an active member of type T and lhs == *rhs.target<T>() is not a constant expression.
template <class ...Ts, class U>
constexpr bool operator!=(variant<Ts...> const& lhs, U const& rhs);
  • Let T be one of the types in Ts... for which rhs is unambiguously convertible to by overload resolution rules.
  • Requires: The expression *lhs.target<T>() != rhs shall be convertible to bool.
  • Returns: If lhs has an active member of type T, *lhs.target<T>() != rhs; otherwise, true.
  • Remarks: This function shall not participate in overload resolution unless there is a type T in Ts... for which rhs is unambiguously convertible to by overload resolution rules, and the expression *lhs.target<T>() != rhs is well-formed. This function shall be a constexpr function unless lhs has an active member of type T and *lhs.target<T>() != rhs is not a constant expression.
template <class U, class ...Ts>
constexpr bool operator!=(U const& lhs, variant<Ts...> const& rhs);
  • Let T be one of the types in Ts... for which lhs is unambiguously convertible to by overload resolution rules.
  • Requires: The expression lhs != *rhs.target<T>() shall be convertible to bool.
  • Returns: If rhs has an active member of type T, lhs != *rhs.target<T>(); otherwise, true.
  • Remarks: This function shall not participate in overload resolution unless there is a type T in Ts... for which lhs is unambiguously convertible to by overload resolution rules, and the expression lhs != *rhs.target<T>() is well-formed. This function shall be a constexpr function unless rhs has an active member of type T and lhs != *rhs.target<T>() is not a constant expression.
template <class ...Ts, class U>
constexpr bool operator<(variant<Ts...> const& lhs, U const& rhs);
  • Let T be one of the types in Ts... for which rhs is unambiguously convertible to by overload resolution rules.
  • Requires: The expression *lhs.target<T>() < rhs shall be convertible to bool.
  • Returns: If !bool(lhs), true; otherwise, if lhs has an active member of type T, *lhs.target<T>() < rhs; otherwise, lhs.which() < I where I is the zero-based index of T in Ts....
  • Remarks: This function shall not participate in overload resolution unless there is a type T in Ts... for which rhs is unambiguously convertible to by overload resolution rules, and the expression *lhs.target<T>() < rhs is well-formed. This function shall be a constexpr function unless lhs has an active member of type T and *lhs.target<T>() < rhs is not a constant expression.
template <class U, class ...Ts>
constexpr bool operator<(U const& lhs, variant<Ts...> const& rhs);
  • Let T be one of the types in Ts... for which lhs is unambiguously convertible to by overload resolution rules.
  • Requires: The expression lhs < *rhs.target<T>() shall be convertible to bool.
  • Returns: If !bool(rhs), false; otherwise, if rhs has an active member of type T, lhs < *rhs.target<T>(); otherwise, I < rhs.which() where I is the zero-based index of T in Ts....
  • Remarks: This function shall not participate in overload resolution unless there is a type T in Ts... for which lhs is unambiguously convertible to by overload resolution rules, and the expression lhs < *rhs.target<T>() is well-formed. This function shall be a constexpr function unless rhs has an active member of type T and lhs < *rhs.target<T>() is not a constant expression.
template <class ...Ts, class U>
constexpr bool operator>(variant<Ts...> const& lhs, U const& rhs);
  • Let T be one of the types in Ts... for which rhs is unambiguously convertible to by overload resolution rules.
  • Requires: The expression *lhs.target<T>() > rhs shall be convertible to bool.
  • Returns: If !bool(lhs), false; otherwise, if lhs has an active member of type T, *lhs.target<T>() > rhs; otherwise, lhs.which() > I where I is the zero-based index of T in Ts....
  • Remarks: This function shall not participate in overload resolution unless there is a type T in Ts... for which rhs is unambiguously convertible to by overload resolution rules, and the expression *lhs.target<T>() > rhs is well-formed. This function shall be a constexpr function unless lhs has an active member of type T and *lhs.target<T>() > rhs is not a constant expression.
template <class U, class ...Ts>
constexpr bool operator>(U const& lhs, variant<Ts...> const& rhs);
  • Let T be one of the types in Ts... for which lhs is unambiguously convertible to by overload resolution rules.
  • Requires: The expression lhs > *rhs.target<T>() shall be convertible to bool.
  • Returns: If !bool(rhs), true; otherwise, if rhs has an active member of type T, lhs > *rhs.target<T>(); otherwise, I > rhs.which() where I is the zero-based index of T in Ts....
  • Remarks: This function shall not participate in overload resolution unless there is a type T in Ts... for which lhs is unambiguously convertible to by overload resolution rules, and the expression lhs > *rhs.target<T>() is well-formed. This function shall be a constexpr function unless rhs has an active member of type T and lhs > *rhs.target<T>() is not a constant expression.
template <class ...Ts, class U>
constexpr bool operator<=(variant<Ts...> const& lhs, U const& rhs);
  • Let T be one of the types in Ts... for which rhs is unambiguously convertible to by overload resolution rules.
  • Requires: The expression *lhs.target<T>() <= rhs shall be convertible to bool.
  • Returns: If !bool(lhs), true; otherwise, if lhs has an active member of type T, *lhs.target<T>() <= rhs; otherwise, lhs.which() < I where I is the zero-based index of T in Ts....
  • Remarks: This function shall not participate in overload resolution unless there is a type T in Ts... for which rhs is unambiguously convertible to by overload resolution rules, and the expression *lhs.target<T>() <= rhs is well-formed. This function shall be a constexpr function unless lhs has an active member of type T and *lhs.target<T>() <= rhs is not a constant expression.
template <class U, class ...Ts>
constexpr bool operator<=(U const& lhs, variant<Ts...> const& rhs);
  • Let T be one of the types in Ts... for which lhs is unambiguously convertible to by overload resolution rules.
  • Requires: The expression lhs <= *rhs.target<T>() shall be convertible to bool.
  • Returns: If !bool(rhs), false; otherwise, if rhs has an active member of type T, lhs <= *rhs.target<T>(); otherwise, I < rhs.which() where I is the zero-based index of T in Ts....
  • Remarks: This function shall not participate in overload resolution unless there is a type T in Ts... for which lhs is unambiguously convertible to by overload resolution rules, and the expression lhs <= *rhs.target<T>() is well-formed. This function shall be a constexpr function unless rhs has an active member of type T and lhs <= *rhs.target<T>() is not a constant expression.
template <class ...Ts, class U>
constexpr bool operator>=(variant<Ts...> const& lhs, U const& rhs);
  • Let T be one of the types in Ts... for which rhs is unambiguously convertible to by overload resolution rules.
  • Requires: The expression *lhs.target<T>() >= rhs shall be convertible to bool.
  • Returns: If !bool(lhs), false; otherwise, if lhs has an active member of type T, *lhs.target<T>() >= rhs; otherwise, lhs.which() > I where I is the zero-based index of T in Ts....
  • Remarks: This function shall not participate in overload resolution unless there is a type T in Ts... for which rhs is unambiguously convertible to by overload resolution rules, and the expression *lhs.target<T>() >= rhs is well-formed. This function shall be a constexpr function unless lhs has an active member of type T and *lhs.target<T>() >= rhs is not a constant expression.
template <class U, class ...Ts>
constexpr bool operator>=(U const& lhs, variant<Ts...> const& rhs);
  • Let T be one of the types in Ts... for which lhs is unambiguously convertible to by overload resolution rules.
  • Requires: The expression lhs >= *rhs.target<T>() shall be convertible to bool.
  • Returns: If !bool(rhs), true; otherwise, if rhs has an active member of type T, lhs >= *rhs.target<T>(); otherwise, I > rhs.which() where I is the zero-based index of T in Ts....
  • Remarks: This function shall not participate in overload resolution unless there is a type T in Ts... for which lhs is unambiguously convertible to by overload resolution rules, and the expression lhs >= *rhs.target<T>() is well-formed. This function shall be a constexpr function unless rhs has an active member of type T and lhs >= *rhs.target<T>() is not a constant expression.

Calling a function with variants of arguments

template <class R, class F, class ...Vs>
constexpr R apply(F&& f, Vs&&... vs);
  • Let Vi be the i-th type in Vs..., Ui be std::decay_t<Vi>, where all indexing is zero-based.
  • Requires: For all i, Ui shall be the type variant<Tsi...> where Tsi is the parameter pack representing the element types in Ui. INVOKE(std::forward<F>(f), get<Is>(std::forward<Vs>(vs))..., R) shall be a valid expression for all Is... in the range [0u, sizeof... (Tsi))....
  • Effects: Equivalent to INVOKE(std::forward<F>(f), get<Is>(std::forward<Vs>(vs))...), R) where Is... are the zero-based indices of the active members of vs....
  • Throws: bad_variant_access if any of vs... has no active member.
  • Remarks: If the selected function is a constant expression, then this function shall be a constexpr function.
template <class F, class ...Vs>
constexpr R apply(F&& f, Vs&&... vs);
  • Let Ri... be the return types of every potentially evaluated INVOKE expression; if every Ri... is the same type, then let R be that type.
  • Effects: Equivalent to apply<R>(std::forward<F>(f), std::forward<Vs>(vs)...).
  • Remarks: This function shall not participate in overload resolution unless the return type of every potentially evaluated INVOKE expression is the same type. If the selected function is a constant expression, then this function shall be a constexpr function.

Specialized algorithms

template <class ...Ts>
constexpr void swap(variant<Ts...>& x, variant<Ts...>& y) noexcept(noexcept(x.swap(y)));
  • Effects: Calls x.swap(y).
  • Remarks: This function shall be defined as deleted unless std::is_move_constructible_v<T> && std::is_swappable_v<T> is true for all T in Ts.... If std::is_trivially_copyable_v<T> && std::is_copy_assignable_v<T> is true for all T in Ts..., then this function shall be a constexpr function.

Hash support

template <class ...Ts>
struct std::hash<eggs::variants::variant<Ts...>>;
  • The specialization std::hash<variant<Ts...>> is enabled if and only if every specialization in std::hash<std::remove_const_t<Ts>>... is enabled. When enabled, for an object v of type variant<Ts...>, if v has an active member of type T, std::hash<variant<Ts...>>()(v) shall evaluate to the same value as std::hash<T>()(*v.target<T>()); otherwise it evaluates to an unspecified value. The member functions are guaranteed to be noexcept if the member functions of every specialization in std::hash<std::remove_const_t<Ts>>... are noexcept.

Copyright Agustín Bergé, Fusion Fenix 2014-2017

Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)