std::variant(3)

πŸ“¦ version 2024.07.05, in nixpkgs unstable, opensuse-leap 16.0

πŸ’– std::variant πŸ’–

okay bestie, welcome to the std::variant(3) page from the C++ Standard Libary (yes, the header literally spells it like that β€” not me, I'm just the messenger 😭). It's giving type-safe union main character energy, and we're gonna read the whole thing together. No cap.

🌸 NAME 🌸

std::variant β€” literally std::variant. That's the whole name, bestie. Iconic minimalism.

✨ Synopsis ✨

Defined in header <variant>.

template< class... Types >   (since C++17)
class variant;

The class template std::variant represents a type-safe union. An instance of std::variant at any given time either holds a value of one of its alternative types, or in the case of error β€” no value (this state is hard to achieve, see valueless_by_exception).

As with unions, if a variant holds a value of some object type T, the object representation of T is allocated directly within the object representation of the variant itself. Variant is not allowed to allocate additional (dynamic) memory.

A variant is not permitted to hold references, arrays, or the type void.

A variant is permitted to hold the same type more than once, and to hold differently cv-qualified versions of the same type.

Consistent with the behavior of unions during aggregate initialization, a default-constructed variant holds a value of its first alternative, unless that alternative is not default-constructible (in which case the variant is not default-constructible either). The helper class std::monostate can be used to make such variants default-constructible.

A program that instantiates the definition of std::variant with no template arguments is ill-formed. std::variant<std::monostate> can be used instead.

bestie, this next one is a big mood: if a program declares an explicit or partial specialization of std::variant, the program is ill-formed, no diagnostic required. Not a vibe check you want to fail. 🫠

🧚 Template parameters 🧚

  • Types β€” the types that may be stored in this variant. All types must meet the Destructible requirements (in particular, array types and non-object types are not allowed).

πŸ’… Member functions πŸ’…

  • constructor β€” constructs the variant object (public member function).
  • destructor β€” destroys the variant, along with its contained value (public member function).
  • operator= β€” assigns a variant (public member function).

🫢 Observers 🫢

  • index β€” returns the zero-based index of the alternative held by the variant (public member function).
  • valueless_by_exception β€” checks if the variant is in the invalid state (public member function).

🌈 Modifiers 🌈

  • emplace β€” constructs a value in the variant, in place (public member function).
  • swap β€” swaps with another variant (public member function).

πŸ¦‹ Visitation πŸ¦‹

  • visit (C++26) β€” calls the provided functor with the argument held by the variant (public member function).

πŸ”₯ Non-member functions πŸ”₯

  • visit (C++17) β€” calls the provided functor with the arguments held by one or more variants (function template).
  • holds_alternative (C++17) β€” checks if a variant currently holds a given type (function template).
  • get(std::variant) (C++17) β€” reads the value of the variant given the index or the type (if the type is unique), throws on error (function template).
  • get_if (C++17) β€” obtains a pointer to the value of a pointed-to variant given the index or the type (if unique), returns null on error (function template).
  • operator==, operator!=, operator<, operator<=, operator>, operator>= (C++17), operator<=> (C++20) β€” compares variant objects as their contained values (function template).
  • std::swap(std::variant) (C++17) β€” specializes the std::swap algorithm (function template).

πŸŽ€ Helper classes πŸŽ€

  • monostate (C++17) β€” placeholder type for use as the first alternative in a variant of non-default-constructible types (class).
  • bad_variant_access (C++17) β€” exception thrown on invalid accesses to the value of a variant (class).
  • variant_size, variant_size_v (C++17) β€” obtains the size of the variant's list of alternatives at compile time (class template) (variable template).
  • variant_alternative, variant_alternative_t (C++17) β€” obtains the type of the alternative specified by its index, at compile time (class template) (alias template).
  • std::hash<std::variant> (C++17) β€” hash support for std::variant (class template specialization).

⭐ Helper objects ⭐

  • variant_npos (C++17) β€” index of the variant in the invalid state (constant).

πŸ“ Notes πŸ“

Feature-test macro: __cpp_lib_variant. Here's the timeline, bestie:

  • 201606L β€” (C++17) β€” std::variant: a type-safe union
  • 202102L β€” (C++17) β€” std::visit for classes derived from std::variant (DR)
  • 202106L β€” (C++20) β€” Fully constexpr std::variant (DR)
  • 202306L β€” (C++26) β€” Member visit

πŸ’» Example πŸ’»

// Run this code

#include <cassert>
#include <iostream>
#include <string>
#include <variant>

int main()
{
    std::variant<int, float> v, w;
    v = 42; // v contains int
    int i = std::get<int>(v);
    assert(42 == i); // succeeds
    w = std::get<int>(v);
    w = std::get<0>(v); // same effect as the previous line
    w = v; // same effect as the previous line

//  std::get<double>(v); // error: no double in [int, float]
//  std::get<3>(v);      // error: valid index values are 0 and 1

    try
    {
        std::get<float>(w); // w contains int, not float: will throw
    }
    catch (const std::bad_variant_access& ex)
    {
        std::cout << ex.what() << '\n';
    }

    using namespace std::literals;

    std::variant<std::string> x("abc");
    // converting constructors work when unambiguous
    x = "def"; // converting assignment also works when unambiguous

    std::variant<std::string, void const*> y("abc");
    // casts to void const * when passed a char const *
    assert(std::holds_alternative<void const*>(y)); // succeeds
    y = "xyz"s;
    assert(std::holds_alternative<std::string>(y)); // succeeds
}

πŸ“ Possible output πŸ“

std::get: wrong index for variant

🧾 Defect reports 🧾

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

  • LWG 2901 β€” applied to C++17 β€” behavior as published: specialization of std::uses_allocator provided, but std::variant cannot properly support allocators β€” correct behavior: specialization removed.
  • LWG 3990 β€” applied to C++17 β€” behavior as published: a program could declare an explicit or partial specialization of std::variant β€” correct behavior: in this case the program is ill-formed, no diagnostic required.

πŸ‘€ See also πŸ‘€

  • in_place, in_place_type, in_place_index, in_place_t, in_place_type_t, in_place_index_t (C++17) β€” in-place construction tag (tag).
  • optional (C++17) β€” a wrapper that may or may not hold an object (class template).
  • any (C++17) β€” objects that hold instances of any CopyConstructible type (class).

that's the entire page, bestie β€” source/version and date: http://cppreference.com Β· 2024.06.10. mwah πŸ’‹βœ¨

πŸ“¦ where this page comes from