Documentation of type_safe

( foonathan/type_safe)

Header file variant.hpp

namespace type_safe
{
    template <typename T>
    using variant_type = union_type<T>;
    
    template <typename ... Ts>
    using variant_types = union_types<Ts...>;
    
    struct nullvar_t;
    
    constexpr nullvar_t nullvar;
    
    template <class VariantPolicy, typename HeadT, typename ... TailT>
    class basic_variant;
    
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator==(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator==(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator!=(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator!=(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator<(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator<(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator<=(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator<=(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator>(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator>(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator>=(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator>=(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    
    template <class VariantPolicy, typename Head, typename ... Types, typename T>
    bool operator==(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);
    template <class VariantPolicy, typename Head, typename ... Types, typename T>
    bool operator==(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    template <class VariantPolicy, typename Head, typename ... Types, typename T>
    bool operator!=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);
    template <class VariantPolicy, typename Head, typename ... Types, typename T>
    bool operator!=(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    template <class VariantPolicy, typename Head, typename ... Types, typename T>
    bool operator<(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);
    template <class VariantPolicy, typename Head, typename ... Types, typename T>
    bool operator<(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    template <class VariantPolicy, typename Head, typename ... Types, typename T>
    bool operator<=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);
    template <class VariantPolicy, typename Head, typename ... Types, typename T>
    bool operator<=(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    template <class VariantPolicy, typename Head, typename ... Types, typename T>
    bool operator>(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);
    template <class VariantPolicy, typename Head, typename ... Types, typename T>
    bool operator>(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    template <class VariantPolicy, typename Head, typename ... Types, typename T>
    bool operator>=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);
    template <class VariantPolicy, typename Head, typename ... Types, typename T>
    bool operator>=(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator==(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator!=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator<(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator<=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator>(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    template <class VariantPolicy, typename Head, typename ... Types>
    bool operator>=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
    
    template <class VariantPolicy, typename Head, typename ... Types, typename Func, typename ... Args>
    void with(basic_variant<VariantPolicy, Head, Types...>& variant, Func&& func, Args&&... additional_args);
    template <class VariantPolicy, typename Head, typename ... Types, typename Func, typename ... Args>
    void with(const basic_variant<VariantPolicy, Head, Types...>& variant, Func&& func, Args&&... additional_args);
    template <class VariantPolicy, typename Head, typename ... Types, typename Func, typename ... Args>
    void with(basic_variant<VariantPolicy, Head, Types...>&& variant, Func&& func, Args&&... additional_args);
    template <class VariantPolicy, typename Head, typename ... Types, typename Func, typename ... Args>
    void with(const basic_variant<VariantPolicy, Head, Types...>&& variant, Func&& func, Args&&... additional_args);
    
    template <typename Fallback>
    class fallback_variant_policy;
    
    template <typename Fallback, typename ... OtherTypes>
    using fallback_variant = basic_variant<fallback_variant_policy<Fallback>, Fallback, OtherTypes...>;
    
    class optional_variant_policy;
    
    using rarely_empty_variant_policy = 'hidden';
    
    using never_empty_variant_policy = 'hidden';
    
    template <typename ... Types>
    using variant = typename detail::select_variant_policy<Types...>::type;
}

Alias template type_safe::variant_type [variant]

template <typename T>
using variant_type = union_type<T>;

Convenience alias for ts::union_type.

Alias template type_safe::variant_types [variant]

template <typename ... Ts>
using variant_types = union_types<Ts...>;

Convenience alias for ts::union_types.

Struct type_safe::nullvar_t [variant]

struct nullvar_t
{
    constexpr nullvar_t();
};

Tag type to mark a ts::basic_variant without a value.

Variable type_safe::nullvar [variant]

constexpr nullvar_t nullvar;

Tag object of type ts::nullvar_t.

Class template type_safe::basic_variant [variant]

template <class VariantPolicy, typename HeadT, typename ... TailT>
class basic_variant
{
public:
    using types = typename union_t::types;
    
    using type_id = typename union_t::type_id;
    
    using allow_empty = typename VariantPolicy::allow_empty;
    
    static constexpr type_id invalid_type = union_t::;
    
    basic_variant() noexcept;
    basic_variant(nullvar_t) noexcept;
    
    basic_variant(const basic_variant&) = default;
    basic_variant(basic_variant&&) = default;
    
    template <typename T, typename ... Args>
    basic_variant(variant_type<T> type, Args&&... args);
    
    template <typename T>
    basic_variant(T&& obj);
    
    basic_variant(const tagged_union<HeadT, TailT...>& u);
    basic_variant(tagged_union<HeadT, TailT...>&& u);
    
    ~basic_variant() noexcept = default;
    
    basic_variant& operator=(const basic_variant&) = default;
    basic_variant& operator=(basic_variant&&) = default;
    
    basic_variant& operator=(nullvar_t) noexcept;
    
    template <typename T>
    basic_variant& operator=(T&& obj);
    
    friend void swap(basic_variant& a, basic_variant& b) noexcept('hidden');
    
    void reset() noexcept;
    
    template <typename T, typename Arg>
    void emplace(variant_type<T> type, Arg&& arg);
    
    template <typename T, typename ... Args>
    void emplace(variant_type<T> type, Args&&... args);
    
    type_id type() const noexcept;
    
    bool has_value() const noexcept;
    operator bool() const noexcept;
    bool has_value(variant_type<nullvar_t>) const noexcept;
    
    template <typename T>
    bool has_value(variant_type<T> type) const noexcept;
    
    nullvar_t value(variant_type<nullvar_t>) const noexcept;
    
    template <typename T>
    T& value(variant_type<T> type) & noexcept;
    template <typename T>
    const T& value(variant_type<T> type) const & noexcept;
    template <typename T>
    T&& value(variant_type<T> type) && noexcept;
    template <typename T>
    const T&& value(variant_type<T> type) const && noexcept;
    
    optional_ref<const nullvar_t> optional_value(variant_type<nullvar_t>) const noexcept;
    
    template <typename T>
    optional_ref<T> optional_value(variant_type<T> type) & noexcept;
    template <typename T>
    optional_ref<const T> optional_value(variant_type<T> type) const & noexcept;
    template <typename T>
    optional_xvalue_ref<T> optional_value(variant_type<T> type) && noexcept;
    template <typename T>
    optional_xvalue_ref<const T> optional_value(variant_type<T> type) const && noexcept;
    
    template <typename T, typename U>
    T value_or(variant_type<T> type, U&& other) const &;
    template <typename T, typename U>
    T value_or(variant_type<T> type, U&& other) &&;
    
    template <typename Functor, typename ... Args, typename Dummy = void, typename = typename std::enable_if<traits::copy_constructible::value, Dummy>::type>
    basic_variant map(Functor&& f, Args&&... args) const &;
    template <typename Functor, typename ... Args, typename Dummy = void, typename = typename std::enable_if<traits::move_constructible::value, Dummy>::type>
    basic_variant map(Functor&& f, Args&&... args) &&;
};

An improved union storing at most one of the given types at a time (or possibly none).

It is an improved version of std::variant. A big problem with variant is implementing the operation that changes the type. It has to destroy the old value and then create the new one. But how to handle an exception when creating the new type? There are multiple ways of handling this, so it is outsourced in a policy. The variant policy is a class that must have the following members:

  • allow_empty - either std::true_type or std::false_type. If it is "true", the variant can be put in the empty state explictly.
  • void change_value(variant_type<T>, tagged_union<Types...>&, Args&&... args) - changes the value and type. It will be called when the variant already contains an object of a different type. It must destroy the old type and create a new one with the given type and arguments.void change_value(variant_type<T>, tagged_union<Types...>&, Args&&... args) - changes the value and type. It will be called when the variant already contains an object of a different type. It must destroy the old type and create a new one with the given type and arguments.

Default constructor type_safe::basic_variant::basic_variant::basic_variant

(1)  basic_variant() noexcept;

(2)  basic_variant(nullvar_t) noexcept;

Effects: Initializes the variant to the empty state.

Notes: This constructor only participates in overload resolution, if the policy allows an empty variant.

Copy constructor type_safe::basic_variant::basic_variant

(1)  basic_variant(const basic_variant&) = default;

(2)  basic_variant(basic_variant&&) = default;

Copy (1)/move (2) constructs a variant.

Effects: If the other variant is not empty, it will call ts::copy (1) or ts::move (2).

Throws: Anything thrown by the copy (1)/move (2) constructor.

Notes: This constructor only participates in overload resolution, if all types are copy (1)/move (2) constructible.

Notes: The move constructor only moves the stored value, and does not make the other variant empty.

Function template type_safe::basic_variant::basic_variant

template <typename T, typename ... Args>
basic_variant(variant_type<T> type, Args&&... args);

Initializes it containing a new object of the given type.

Effects: Creates it by calling Ts constructor with the perfectly forwarded arguments.

Throws: Anything thrown by Ts constructor.

Notes: This constructor does not participate in overload resolution, unless T is a valid type for the variant and constructible from the arguments.

Function template type_safe::basic_variant::basic_variant

template <typename T>
basic_variant(T&& obj);

Initializes it with a copy of the given object.

Effects: Same as the type + argument constructor called with the decayed type of the argument and the object perfectly forwarded.

Throws: Anything thrown by Ts copy/move constructor.

Notes: This constructor does not participate in overload resolution, unless T is a valid type for the variant and copy/move constructible.

Constructor type_safe::basic_variant::basic_variant

(1)  basic_variant(const tagged_union<HeadT, TailT...>& u);

(2)  basic_variant(tagged_union<HeadT, TailT...>&& u);

Initializes it from a ts::tagged_union.

Effects: Copies the currently stored type of the union into the variant by calling the copy (1)/move (2) constructor of the stored type.

Throws: Anything thrown by the selected copy (1)/move (2) constructor.

Requires: If the variant policy does not allow the empty state, the union must not be empty.

Destructor type_safe::basic_variant::~basic_variant

~basic_variant() noexcept = default;

Effects: Destroys the currently stored value, if there is any.

Assignment operator type_safe::basic_variant::operator=

(1)  basic_variant& operator=(const basic_variant&) = default;

(2)  basic_variant& operator=(basic_variant&&) = default;

Copy (1)/move (2) assigns a variant.

Effects: If the other variant is empty, makes this one empty as well. Otherwise let the other variant contains an object of type T. If this variant contains the same type and there is a copy (1)/move (2) assignment operator available, assigns the object to this object. Else forwards to the variant policy's change_value() function.

Throws: Anything thrown by either the copy (1)/move (2) assignment operator or copy (1)/move (2) constructor. If the assignment operator throws, the variant will contain the partially assigned object. If the constructor throws, the state depends on the variant policy.

Notes: This function does not participate in overload resolution, unless all types are copy (1)/move (2) constructible.

Assignment operator type_safe::basic_variant::operator=::operator=

basic_variant& operator=(nullvar_t) noexcept;

Alias for reset().

Assignment operator type_safe::basic_variant::operator=

template <typename T>
basic_variant& operator=(T&& obj);

Same as the single argument emplace().

Effects: Changes the value to a copy of obj.

Throws: Anything thrown by Ts copy/move constructor.

Notes: This function does not participate in overload resolution, unless T is a valid type for the variant and copy/move constructible.

Function type_safe::swap

friend void swap(basic_variant& a, basic_variant& b) noexcept('hidden');

Swaps two variants.

Effects: There are four cases:

  • Both variants are empty. Then the function has no effect.
  • Both variants contain the same type, T. Then it calls swap on the stored type.
  • Both variants contain a type, but different types. Then it swaps the variant by move constructing the objects from one type to the other, using the variant policy.
  • Only one variant contains an object. Then it moves the value to the empty variant, and destroys it in the non-empty variant.

Effects: In either case, it will only call the swap() function or the move constructor.

Throws: Anything thrown by the swap function, in which case both variants contain the partially swapped values, or the mvoe constructor, in which case the exact behavior depends on the variant policy.

Function template type_safe::basic_variant::reset::reset

void reset() noexcept;

Effects: Destroys the stored value in the variant, if any.

Notes: This function only participate in overload resolution, if the variant policy allows the empty state.

Function template type_safe::basic_variant::emplace

template <typename T, typename Arg>
void emplace(variant_type<T> type, Arg&& arg);

Changes the value to a new object of the given type.

Effects: If the variant contains an object of the same type, assigns the argument to it. Otherwise behaves as the other emplace version.

Throws: Anything thrown by the chosen assignment operator or the other emplace(). If the assignment operator throws, the variant contains a partially assigned oject. Otherwise it depends on the variant policy.

Notes: This function does not participate in overload resolution, unless T is a valid type for the variant and assignable from the argument without creating an additional temporary.

Function template type_safe::basic_variant::emplace

template <typename T, typename ... Args>
void emplace(variant_type<T> type, Args&&... args);

Changes the value to a new object of given type.

Effects: If variant is empty, creates the object directly inplace by perfectly forwarding the arguments. Otherwise it forwards to the variant policy's change_value() function.

Throws: Anything thrown by Ts constructor or possibly move constructor. If the variant was empty before, it is still empty afterwards. Otherwise the state depends on the policy.

Notes: This function does not participate in overload resolution, unless T is a valid type for the variant and constructible from the arguments.

Function type_safe::basic_variant::type

type_id type() const noexcept;

Returns: The type id representing the type of the value currently stored in the variant.

Notes: If it does not have a value stored, returns invalid_type.

Function type_safe::basic_variant::has_value

(1)  bool has_value() const noexcept;

(2)  operator bool() const noexcept;

(3)  bool has_value(variant_type<nullvar_t>) const noexcept;

Returns: true if the variant currently contains a value, false otherwise.

Notes: Depending on the variant policy, it can be guaranteed to return true all the time.

Function template type_safe::basic_variant::has_value

template <typename T>
bool has_value(variant_type<T> type) const noexcept;

Returns: true if the variant currently stores an object of type T, false otherwise.

Notes: T must not necessarily be a type that can be stored in the variant.

Function type_safe::basic_variant::value

nullvar_t value(variant_type<nullvar_t>) const noexcept;

Returns: A copy of ts::nullvar.

Requires: The variant must be empty.

Function template type_safe::basic_variant::value

(1)  template <typename T>
     T& value(variant_type<T> type) & noexcept;

(2)  template <typename T>
     const T& value(variant_type<T> type) const & noexcept;

(3)  template <typename T>
     T&& value(variant_type<T> type) && noexcept;

(4)  template <typename T>
     const T&& value(variant_type<T> type) const && noexcept;

Returns: A (const) lvalue (1, 2)/rvalue (3, 4) reference to the stored object of the given type.

Requires: The variant must currently store an object of the given type, i.e. has_value(type) must return true.

Function type_safe::basic_variant::optional_value

optional_ref<const nullvar_t> optional_value(variant_type<nullvar_t>) const noexcept;

Returns: A ts::optional_ref to ts::nullvar. If the variant is not empty, returns a null reference.

Function template type_safe::basic_variant::optional_value

(1)  template <typename T>
     optional_ref<T> optional_value(variant_type<T> type) & noexcept;

(2)  template <typename T>
     optional_ref<const T> optional_value(variant_type<T> type) const & noexcept;

(3)  template <typename T>
     optional_xvalue_ref<T> optional_value(variant_type<T> type) && noexcept;

(4)  template <typename T>
     optional_xvalue_ref<const T> optional_value(variant_type<T> type) const && noexcept;

Returns: A (const) ts::optional_ref (1, 2)/ts::optional_xvalue_ref to the stored value of given type. If it stores a different type, returns a null reference.

Function template type_safe::basic_variant::value_or

(1)  template <typename T, typename U>
     T value_or(variant_type<T> type, U&& other) const &;

(2)  template <typename T, typename U>
     T value_or(variant_type<T> type, U&& other) &&;

Returns: If the variant currently stores an object of type T, returns a copy of that by copy (1)/move (2) constructing. Otherwise returns other converted to T.

Throws: Anything thrown by Ts copy (1)/move (2) constructor or the converting constructor.

Notes: T must not necessarily be a type that can be stored in the variant.

Notes: This function does not participate in overload resolution, unless T is copy (1)/move (2) constructible and the fallback convertible to T.

Function template type_safe::basic_variant::map

(1)  template <typename Functor, typename ... Args, typename Dummy = void, typename = typename std::enable_if<traits::copy_constructible::value, Dummy>::type>
     basic_variant map(Functor&& f, Args&&... args) const &;

(2)  template <typename Functor, typename ... Args, typename Dummy = void, typename = typename std::enable_if<traits::move_constructible::value, Dummy>::type>
     basic_variant map(Functor&& f, Args&&... args) &&;

Maps a variant with a function.

Effects: If the variant is not empty, calls the function using either std::forward<Functor>(f)(current-value, std::forward<Args>(args)...) or member call syntax (current-value.*std::forward<Functor>(f))(std::forward<Args>(args)...). If those two expressions are both ill-formed, does nothing.

Returns: A new variant of the same type. It contains nothing, if *this contains nothing. Otherwise, if the function was called, it contains the result of the function. Otherwise, it is a copy of the current variant.

Throws: Anything thrown by the function or copy/move constructor, in which case the variant will be left unchanged, unless the object was already moved into the function and modified there.

Requires: The result of the function - if it is called - can be stored in the variant.

Notes: (1) will use the copy constructor, (2) will use the move constructor. The function does not participate in overload resolution, if copy (1)/move (2) constructors are not available for all types.


Comparison operator type_safe::operator== [variant]

(1)  template <class VariantPolicy, typename Head, typename ... Types>
     bool operator==(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);

(2)  template <class VariantPolicy, typename Head, typename ... Types>
     bool operator==(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);

(3)  template <class VariantPolicy, typename Head, typename ... Types>
     bool operator!=(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);

(4)  template <class VariantPolicy, typename Head, typename ... Types>
     bool operator!=(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);

(5)  template <class VariantPolicy, typename Head, typename ... Types>
     bool operator<(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);

(6)  template <class VariantPolicy, typename Head, typename ... Types>
     bool operator<(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);

(7)  template <class VariantPolicy, typename Head, typename ... Types>
     bool operator<=(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);

(8)  template <class VariantPolicy, typename Head, typename ... Types>
     bool operator<=(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);

(9)  template <class VariantPolicy, typename Head, typename ... Types>
     bool operator>(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);

(10)  template <class VariantPolicy, typename Head, typename ... Types>
     bool operator>(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);

(11)  template <class VariantPolicy, typename Head, typename ... Types>
     bool operator>=(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);

(12)  template <class VariantPolicy, typename Head, typename ... Types>
     bool operator>=(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);

Compares a ts::basic_variant with ts::nullvar.

A variant compares equal to nullvar, when it does not have a value. A variant compares never less to nullvar, nullvar compares less only if the variant has a value. The other comparisons behave accordingly.

Comparison operator type_safe::operator== [variant]

(1)  template <class VariantPolicy, typename Head, typename ... Types, typename T>
     bool operator==(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);

(2)  template <class VariantPolicy, typename Head, typename ... Types, typename T>
     bool operator==(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);

(3)  template <class VariantPolicy, typename Head, typename ... Types, typename T>
     bool operator!=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);

(4)  template <class VariantPolicy, typename Head, typename ... Types, typename T>
     bool operator!=(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);

(5)  template <class VariantPolicy, typename Head, typename ... Types, typename T>
     bool operator<(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);

(6)  template <class VariantPolicy, typename Head, typename ... Types, typename T>
     bool operator<(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);

(7)  template <class VariantPolicy, typename Head, typename ... Types, typename T>
     bool operator<=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);

(8)  template <class VariantPolicy, typename Head, typename ... Types, typename T>
     bool operator<=(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);

(9)  template <class VariantPolicy, typename Head, typename ... Types, typename T>
     bool operator>(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);

(10)  template <class VariantPolicy, typename Head, typename ... Types, typename T>
     bool operator>(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);

(11)  template <class VariantPolicy, typename Head, typename ... Types, typename T>
     bool operator>=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);

(12)  template <class VariantPolicy, typename Head, typename ... Types, typename T>
     bool operator>=(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);

Compares a ts::basic_variant with a value.

A variant compares equal to a value, if it contains an object of the same type and the object compares equal. A variant compares less to a value, if - when it has a different type - the type id compares less than the type id of the value, or - when it has the same type - the object compares less to the value. The other comparisons behave accordingly.

Notes: The value must not necessarily have a type that can be stored in the variant.

Comparison operator type_safe::operator== [variant]

(1)  template <class VariantPolicy, typename Head, typename ... Types>
     bool operator==(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);

(2)  template <class VariantPolicy, typename Head, typename ... Types>
     bool operator!=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);

(3)  template <class VariantPolicy, typename Head, typename ... Types>
     bool operator<(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);

(4)  template <class VariantPolicy, typename Head, typename ... Types>
     bool operator<=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);

(5)  template <class VariantPolicy, typename Head, typename ... Types>
     bool operator>(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);

(6)  template <class VariantPolicy, typename Head, typename ... Types>
     bool operator>=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);

Compares two ts::basic_variants.

They compare equal if both store the same type (or none) and the stored object compares equal. A variant is less than another if they store mismatched types and the type id of the first is less than the other, or if they store the same type and the stored object compares less. The other comparisons behave accordingly.

Function template type_safe::with [variant]

(1)  template <class VariantPolicy, typename Head, typename ... Types, typename Func, typename ... Args>
     void with(basic_variant<VariantPolicy, Head, Types...>& variant, Func&& func, Args&&... additional_args);

(2)  template <class VariantPolicy, typename Head, typename ... Types, typename Func, typename ... Args>
     void with(const basic_variant<VariantPolicy, Head, Types...>& variant, Func&& func, Args&&... additional_args);

(3)  template <class VariantPolicy, typename Head, typename ... Types, typename Func, typename ... Args>
     void with(basic_variant<VariantPolicy, Head, Types...>&& variant, Func&& func, Args&&... additional_args);

(4)  template <class VariantPolicy, typename Head, typename ... Types, typename Func, typename ... Args>
     void with(const basic_variant<VariantPolicy, Head, Types...>&& variant, Func&& func, Args&&... additional_args);

Effects: If the variant is empty, does nothing. Otherwise let the variant contain an object of type T. If the functor is callable for the T, calls its operator() passing it the stored object. Else does nothing.

Class template type_safe::fallback_variant_policy [variant]

template <typename Fallback>
class fallback_variant_policy
{
public:
    using allow_empty = std::false_type;
    
    template <typename T, typename ... Types, typename ... Args>
    static void change_value(union_type<T> type, tagged_union<Types...>& storage, Args&&... args);
};

A variant policy for ts::basic_variant that uses a fallback type.

When changing the type of the variant throws an exception, the variant will create an object of the fallback type instead. The variant will never be empty.

Requires: Fallback must be nothrow default constructible and a type that can be stored in the variant.

Alias template type_safe::fallback_variant [variant]

template <typename Fallback, typename ... OtherTypes>
using fallback_variant = basic_variant<fallback_variant_policy<Fallback>, Fallback, OtherTypes...>;

A ts::basic_variant using the ts::fallback_variant_policy.

This is a variant that is never empty, where exceptions on changing the type leaves it with a default-constructed object of the Fallback type.

Requires: Fallback must be nothrow default constructible.

Class type_safe::optional_variant_policy [variant]

class optional_variant_policy
{
public:
    using allow_empty = std::true_type;
    
    template <typename T, typename ... Types, typename ... Args>
    static void change_value(union_type<T> type, tagged_union<Types...>& storage, Args&&... args);
};

A variant policy for ts::basic_variant that creates a variant with explicit empty state.

It allows an empty variant explicitly. When changing the type of the variant throws an exception, the variant will be left in that empty state.

Type alias type_safe::rarely_empty_variant_policy [variant]

using rarely_empty_variant_policy = 'hidden';

A variant policy for ts::basic_variant that creates a variant which is rarely empty.

When changing the type of the variant, it will use a the move constructor with a temporary. If the move constructor throws, the variant will be left in the empty state. Putting it into the empty state explictly is not allowed.

Type alias type_safe::never_empty_variant_policy [variant]

using never_empty_variant_policy = 'hidden';

A variant policy for ts::basic_variant that creates a variant which is never empty.

Similar to ts::rarely_empty_variant_policy but when the move constructor throws, it calls std::terminate().

Alias template type_safe::variant [variant]

template <typename ... Types>
using variant = typename detail::select_variant_policy<Types...>::type;

A ts::basic_variant with the recommended default semantics.

If the first type is ts::nullvar_t it will use the ts::optional_variant_policy, which explicitly allows the empty state. Otherwise it will use the ts::rarely_empty_variant_policy where it tries to avoid the empty state as good as possible.

Notes: If you pass ts::nullvar_t as the first type, it is not actually one of the types that can be stored in the variant, but a tag to enable the empty state.