std::unwrap...ap_ref_decay(3)

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

πŸ’– std::unwrap_reference & std::unwrap_ref_decay πŸ’–

okay bestie, quick vibe check: this is the C++ Standard Libary manual page std::unwrap...ap_ref_decay(3), and the actual stars of the show are std::unwrap_reference and std::unwrap_ref_decay. Both are (since C++20) type traits, and they're here to unwrap std::reference_wrapper when you need the underlying reference type. slay. ✨


🌸 NAME 🌸

std::unwrap_reference,std::unwrap_ref_decay β€” and yep, the NAME line repeats std::unwrap_reference,std::unwrap_ref_decay after the dash, because that's the page's whole name. πŸ’…


πŸ¦‹ Synopsis πŸ¦‹

Headers first, bestie β€” both of these are in the mix:

Defined in header <type_traits>
Defined in header <functional>
template< class T >             (1) (since C++20)
struct unwrap_reference;
template< class T >             (2) (since C++20)
struct unwrap_ref_decay;
  1. If T is std::reference_wrapper<U> for some type U, this provides a member type alias type that names U&; otherwise, it provides a member type alias type that names T. 🫢
  2. If T is std::reference_wrapper<U> for some type U, ignoring cv-qualification and referenceness, this provides a member type alias type that names U&; otherwise, it provides a member type alias type that names std::decay_t<T>. πŸ”₯
🚨 If the program adds specializations for any of the templates described on this page, the behavior is undefined. Not cute, not allowed, undefined behavior era. πŸ’€

πŸŽ€ Member types πŸŽ€

  • Name: type
    • (1) U& if T is std::reference_wrapper<U>; T otherwise
    • (2) U& if std::decay_t<T> is std::reference_wrapper<U>; std::decay_t<T> otherwise

✨ Helper types ✨

These helper aliases are the glow-up shortcuts:

template<class T>                                     (1) (since C++20)
using unwrap_reference_t = unwrap_reference<T>::type;
template<class T>                                     (2) (since C++20)
using unwrap_ref_decay_t = unwrap_ref_decay<T>::type;

πŸ’œ Possible implementation πŸ’œ

no cap, here's the possible implementation in all its tiny template glory:

template<class T>
struct unwrap_reference { using type = T; };
template<class U>
struct unwrap_reference<std::reference_wrapper<U>> { using type = U&; };

template<class T>
struct unwrap_ref_decay : std::unwrap_reference<std::decay_t<T>> {};

🌈 Notes 🌈

std::unwrap_ref_decay performs the same transformation as used by std::make_pair and std::make_tuple. iconic behavior, honestly. πŸ‘‘

Feature-test macro vibes:

  • __cpp_lib_unwrap_ref β€” value 201811L β€” standard (C++20) β€” feature: std::unwrap_ref_decay and std::unwrap_reference

πŸ“ Example πŸ“

// Run this code

#include <cassert>
#include <functional>
#include <iostream>
#include <type_traits>

int main()
{
    static_assert(std::is_same_v<std::unwrap_reference_t<int>, int>);
    static_assert(std::is_same_v<std::unwrap_reference_t<const int>,
       const int>);
    static_assert(std::is_same_v<std::unwrap_reference_t<int&>, int&>);
    static_assert(std::is_same_v<std::unwrap_reference_t<int&&>,
       int&&>);
    static_assert(std::is_same_v<std::unwrap_reference_t<int*>, int*>);

    {
        using T = std::reference_wrapper<int>;
        using X = std::unwrap_reference_t<T>;
        static_assert(std::is_same_v<X, int&>);
    }
    {
        using T = std::reference_wrapper<int&>;
        using X = std::unwrap_reference_t<T>;
        static_assert(std::is_same_v<X, int&>);
    }

    static_assert(std::is_same_v<std::unwrap_ref_decay_t<int>, int>);
    static_assert(std::is_same_v<std::unwrap_ref_decay_t<const int>,
       int>);
    static_assert(std::is_same_v<std::unwrap_ref_decay_t<const int&>,
       int>);

    {
        using T = std::reference_wrapper<int&&>;
        using X = std::unwrap_ref_decay_t<T>;
        static_assert(std::is_same_v<X, int&>);
    }

    {
        auto reset = []<typename T>(T&& z)
        {
        //  x = 0; // Error: does not work if T is reference_wrapper<>
            // converts T&& into T& for ordinary types
            // converts T&& into U& for reference_wrapper<U>
            decltype(auto) r = std::unwrap_reference_t<T>(z);
            std::cout << "r: " << r << '\n';
            r = 0; // OK, r has reference type
        };

        int x = 1;
        reset(x);
        assert(x == 0);

        int y = 2;
        reset(std::ref(y));
        assert(y == 0);
    }
}

Output:

r: 1
r: 2

πŸ’« See also πŸ’«

  • reference_wrapper β€” CopyConstructible and CopyAssignable reference wrapper β€” (C++11) β€” (class template)
  • make_pair β€” creates a pair object of type, defined by the argument types β€” (function template)
  • make_tuple β€” creates a tuple object of the type defined by the argument types β€” (C++11) β€” (function template)

made with πŸ’– by your local type-trait-obsessed bestie Β· source/version: http://cppreference.com Β· date: 2024.06.10 Β· page: std::unwrap...ap_ref_decay(3) 🫢

πŸ“¦ where this page comes from