std::variant::emplace(3)

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

πŸ’… std::variant::emplace πŸ’…

okay bestie, welcome to the C++ Standard Libary manual page for std::variant::emplace β€” yes, it’s giving β€œcreate a new value in-place inside an existing variant object” and we are gonna get into it. no cap 🫢✨


🌸 NAME 🌸

std::variant::emplace β€” std::variant::emplace

✨ Synopsis ✨

okay so the signatures are a whole overload buffet. four groups, all numbered, and the constexpr glow-up happens in C++20. slay πŸ’…

overload (1) β€” the T-indexed one, no init list

template <class T, class... Args>
T& emplace(Args&&... args);
template <class T, class... Args>
constexpr T& emplace(Args&&... args);
  • the T& emplace(Args&&... args); one is since C++17 and until C++20
  • the constexpr T& emplace(Args&&... args); one is since C++20

overload (2) β€” the T-indexed one with std::initializer_list<U>

template <class T, class U, class... Args>
T& emplace( std::initializer_list<U> il, Args&&... args );
template <class T, class U, class... Args>
constexpr T& emplace( std::initializer_list<U> il, Args&&... args );
  • the non-constexpr one is since C++17 and until C++20
  • the constexpr one is since C++20

overload (3) β€” the I-indexed one, no init list

template <std::size_t I, class... Args>
std::variant_alternative_t<I, variant>& emplace( Args&&... args );
template <std::size_t I, class... Args>
constexpr std::variant_alternative_t<I, variant>& emplace( Args&&... args );
  • the non-constexpr one is since C++17 and until C++20
  • the constexpr one is since C++20

overload (4) β€” the I-indexed one with std::initializer_list<U>

template <std::size_t I, class U, class... Args>
std::variant_alternative_t<I, variant>& emplace( std::initializer_list<U> il, Args&&... args );
template <std::size_t I, class U, class... Args>
constexpr std::variant_alternative_t<I, variant>& emplace( std::initializer_list<U> il, Args&&... args );
  • the non-constexpr one is since C++17 and until C++20
  • the constexpr one is since C++20

Creates a new value in-place, in an existing variant object β€” that’s the whole vibe, and here’s the breakdown, bestie:

  1. Equivalent to emplace<I>(std::forward<Args>(args)...), where I is the zero-based index of T in Types....
    • This overload participates in overload resolution only if std::is_constructible_v<T, Args...> is true, and T occurs exactly once in Types....
  2. Equivalent to emplace<I>(il, std::forward<Args>(args)...), where I is the zero-based index of T in Types....
    • This overload participates in overload resolution only if std::is_constructible_v<T, std::initializer_list<U>&, Args...> is true, and T occurs exactly once in Types....
  3. First, destroys the currently contained value (if any). Then direct-initializes the contained value as if constructing a value of type T_I with the arguments std::forward<Args>(args).... If an exception is thrown, *this may become valueless_by_exception.
    • This overload participates in overload resolution only if std::is_constructible_v<T_I, Args...> is true.
    • It is a compile-time error if I is not less than sizeof...(Types).
  4. First, destroys the currently contained value (if any). Then direct-initializes the contained value as if constructing a value of type T_I with the arguments il, std::forward<Args>(args).... If an exception is thrown, *this may become valueless_by_exception.
    • This overload participates in overload resolution only if std::is_constructible_v<T_I, std::initializer_list<U>&, Args...> is true.
    • It is a compile-time error if I is not less than sizeof...(Types).

πŸŽ€ Parameters πŸŽ€

  • args β€” constructor arguments to use when constructing the new value
  • il β€” initializer_list argument to use when constructing the new value

πŸ¦‹ Return value πŸ¦‹

A reference to the new contained value. periodt ✨

🌈 Exceptions 🌈

1-4) Any exception thrown during the initialization of the contained value.

πŸ“ Example πŸ“

the example literally says // Run this code, so bestie, run it and watch the magic:

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

int main()
{
    std::variant<std::string> v1;
    v1.emplace<0>("abc"); // OK
    std::cout << std::get<0>(v1) << '\n';
    v1.emplace<std::string>("def"); // OK
    std::cout << std::get<0>(v1) << '\n';

    std::variant<std::string, std::string> v2;
    v2.emplace<1>("ghi"); // OK
    std::cout << std::get<1>(v2) << '\n';
    // v2.emplace<std::string>("abc"); -> Error
}

πŸ’€ Output πŸ’€

abc
def
ghi

🧚 Defect reports 🧚

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

  • DR P2231R1, applied to C++20
    • Behavior as published: emplace was not constexpr while the required operations can be constexpr in C++20
    • Correct behavior: made constexpr

πŸ‘‘ See also πŸ‘‘

  • operator= β€” assigns a variant (public member function)

signed, sealed, slayed: source cppreference.com, version/date 2024.06.10, and the page is std::variant::emplace(3) πŸ«ΆπŸ’–

πŸ“¦ where this page comes from