std::remove_reference în C++

remove_reference scoate referința dintr-un tip; decay îl transformă ca la transmiterea prin valoare.

Sintaxă
#include <type_traits>
std::remove_reference_t<T>   // T& și T&& devin T
std::decay_t<T>              // ca la transmiterea prin valoare

Ce face std::remove_reference

std::remove_reference_t<int&> și std::remove_reference_t<int&&> sunt amândouă int. const rămâne: const int& devine const int. Pentru a scoate și referința, și const, există std::remove_cvref_t (C++20).

std::decay_t<T> face ce face compilatorul când transmiți ceva prin valoare: scoate referința și const, transformă un tablou în pointer (int[5] devine int*) și o funcție în pointer la funcție. Este util în șabloane care păstrează o copie a argumentelor (așa face std::thread).

Parametri

Parametru Descriere
T Tipul transformat.

Ce returnează

Tipul transformat.

Exemple

Exemplul 1: Ce rămâne după transformare

#include <print>
#include <type_traits>

int main() {
    std::println("remove_reference<int&> == int: {}", std::is_same_v<std::remove_reference_t<int&>, int>);
    std::println("remove_reference<const int&> == const int: {}",
                 std::is_same_v<std::remove_reference_t<const int&>, const int>);

    std::println("decay<const int&> == int: {}", std::is_same_v<std::decay_t<const int&>, int>);
    std::println("decay<int[5]> == int*: {}", std::is_same_v<std::decay_t<int[5]>, int*>);
    std::println("decay<int(double)> == int(*)(double): {}",
                 std::is_same_v<std::decay_t<int(double)>, int (*)(double)>);
}

Rezultat

remove_reference<int&> == int: true
remove_reference<const int&> == const int: true
decay<const int&> == int: true
decay<int[5]> == int*: true
decay<int(double)> == int(*)(double): true

Exemplul 2: Copia unui argument primit prin referință universală

T poate fi std::string&; ca să păstrăm o copie, avem nevoie de tipul fără referință.

#include <print>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>

template <class T>
auto puneInLista(T&& valoare) {
    std::vector<std::decay_t<T>> lista;
    lista.push_back(std::forward<T>(valoare));
    return lista;
}

int main() {
    std::string oras = "Sibiu";
    auto lista = puneInLista(oras);   // T este std::string&
    std::println("{} element(e): {}", lista.size(), lista[0]);
    std::println("tipul elementelor este std::string: {}",
                 std::is_same_v<decltype(lista)::value_type, std::string>);
}

Rezultat

1 element(e): Sibiu
tipul elementelor este std::string: true

Greșeli frecvente

  • Folosești remove_reference_t și te aștepți să dispară și const. Rămâne; folosește std::remove_cvref_t sau std::decay_t.

Comenzi înrudite

  • std::is_same: Verifică la compilare dacă două tipuri sunt exact același tip.
  • std::forward: Transmite un argument mai departe păstrând felul lui: valoare temporară (mutabilă) sau variabilă cu nume.
  • decltype: Dă tipul exact al unei expresii, fără să o evalueze; util pentru a declara variabile „de același tip ca”.
  • std::move: Mută elementele unui interval la o destinație, fără să le copieze (versiunea din <algorithm>).