web-dev-qa-db-fra.com

Comment utiliser correctement std :: reference_wrappers

J'essaie de comprendre std::reference_wrapper.

Le code suivant montre que l'encapsuleur de référence ne se comporte pas exactement comme une référence.

#include <iostream>
#include <vector>
#include <functional>

int main()
{
    std::vector<int> numbers = {1, 3, 0, -8, 5, 3, 1};

    auto referenceWrapper = std::ref(numbers);
    std::vector<int>& reference = numbers;

    std::cout << reference[3]              << std::endl;
    std::cout << referenceWrapper.get()[3] << std::endl; 
              // I need to use get ^
              // otherwise does not compile.
    return 0;
}

Si je comprends bien, la conversion implicite ne s'applique pas à l'appel des fonctions membres. Est-ce une limitation inhérente? Dois-je utiliser le std::reference_wrapper::get si souvent?

Un autre cas est le suivant:

#include <iostream>
#include <functional>

int main()
{
    int a = 3;
    int b = 4;
    auto refa = std::ref(a);
    auto refb = std::ref(b);
    if (refa < refb)
        std::cout << "success" << std::endl;

    return 0;
}

Cela fonctionne bien, mais lorsque j'ajoute cela au-dessus de la définition main:

template <typename T>
bool operator < (T left, T right)
{
    return left.someMember();
}

Le compilateur essaie d'instancier le modèle et oublie la conversion implicite et l'opérateur intégré.

Ce comportement est-il inhérent ou ai-je mal compris quelque chose de crucial à propos de std::reference_wrapper?

39
Martin Drozdik

La classe std::reference_wrapper<T> Implémente un opérateur de conversion implicite en T&:

operator T& () const noexcept;

et un getter plus explicite:

T& get() const noexcept;

L'opérateur implicite est appelé lorsqu'un T (ou T&) Est requis. Par exemple

void f(some_type x);
// ...
std::reference_wrapper<some_type> x;
some_type y = x; // the implicit operator is called
f(x);            // the implicit operator is called and the result goes to f.

Cependant, parfois un T n'est pas nécessairement attendu et, dans ce cas, vous devez utiliser get. Cela se produit, principalement, dans des contextes de déduction de type automatique. Par exemple,

template <typename U>
g(U x);
// ...
std::reference_wrapper<some_type> x;
auto y = x; // the type of y is std::reference_wrapper<some_type>
g(x);       // U = std::reference_wrapper<some_type>

Pour obtenir some_type Au lieu de std::reference_wrapper<some_type> Ci-dessus, vous devez faire

auto y = x.get(); // the type of y is some_type
g(x.get());       // U = some_type

Alternativement, la dernière ligne ci-dessus pourrait être remplacée par g<some_type>(x);. Cependant, pour les opérateurs modélisés (par exemple ostream::operator <<()) je crois que vous ne pouvez pas expliquer le type.

43
Cassio Neri