J'ai quelques questions concernant ce programme:
#include <iostream>
#include <type_traits>
#include <functional>
using namespace std;
template <typename T> void foo ( T x )
{
auto r=ref(x);
cout<<boolalpha;
cout<<is_same<T&,decltype(r)>::value;
}
int main()
{
int x=5;
foo (x);
return 0;
}
La sortie est:
false
Je veux savoir si std::ref
ne retourne pas la référence d'un objet, que fait-il alors? En gros, quelle est la différence entre:
T x;
auto r = ref(x);
et
T x;
T &y = x;
Aussi, je veux savoir pourquoi cette différence existe? Pourquoi avons-nous besoin std::ref
ou std::reference_wrapper
lorsque nous avons des références (c.-à-d. T&
)?
Eh bien ref
construit un objet du type reference_wrapper
Approprié pour contenir une référence à un objet. Ce qui signifie quand vous postulez:
auto r = ref(x);
Ceci retourne un reference_wrapper
Et non une référence directe à x
(c'est-à-dire T&
). Ce reference_wrapper
(C'est-à-dire r
) contient plutôt T&
.
Un reference_wrapper
Est très utile lorsque vous souhaitez émuler un reference
d’un objet pouvant être copié (il est à la fois copy-constructible et copy- assignable).
En C++, une fois que vous créez une référence (disons y
) à un objet (disons x
), alors y
et x
partagent le même message adresse de base. De plus, y
ne peut faire référence à aucun autre objet. De plus, vous ne pouvez pas créer un tableau de références c'est-à-dire qu'un code comme celui-ci déclenchera une erreur:
#include <iostream>
using namespace std;
int main()
{
int x=5, y=7, z=8;
int& arr[] {x,y,z}; // error: declaration of 'arr' as array of references
return 0;
}
Cependant c'est légal:
#include <iostream>
#include <functional> // for reference_wrapper
using namespace std;
int main()
{
int x=5, y=7, z=8;
reference_wrapper<int> arr[] {x,y,z};
for (auto a: arr)
cout << a << " ";
return 0;
}
/* OUTPUT:
5 7 8
*/
En parlant de votre problème avec cout << is_same<T&,decltype(r)>::value;
, la solution est la suivante:
cout << is_same<T&,decltype(r.get())>::value; // will yield true
Laissez-moi vous montrer un programme:
#include <iostream>
#include <type_traits>
#include <functional>
using namespace std;
int main()
{
cout << boolalpha;
int x=5, y=7;
reference_wrapper<int> r=x; // or auto r = ref(x);
cout << is_same<int&, decltype(r.get())>::value << "\n";
cout << (&x==&r.get()) << "\n";
r=y;
cout << (&y==&r.get()) << "\n";
r.get()=70;
cout << y;
return 0;
}
/* Ouput:
true
true
true
70
*/
Nous voyons ici trois choses à savoir:
Un objet reference_wrapper
(Ici r
) peut être utilisé pour créer un tableau de références, ce qui n’était pas possible avec T&
.
r
agit en réalité comme une référence réelle (voir comment r.get()=70
a changé la valeur de y
).
r
n'est pas identique à T&
mais r.get()
est. Cela signifie que r
détient T&
, C'est-à-dire comme son nom l'indique est un enveloppe autour d'une référenceT&
.
J'espère que cette réponse est plus que suffisante pour expliquer vos doutes.
std::reference_wrapper
Est reconnu par les installations standard pour pouvoir transmettre des objets par référence dans des contextes de définition de valeur.
Par exemple, std::bind
Peut intégrer la std::ref()
à quelque chose, la transmettre par valeur et la décompresser ultérieurement dans une référence.
void print(int i) {
std::cout << i << '\n';
}
int main() {
int i = 10;
auto f1 = std::bind(print, i);
auto f2 = std::bind(print, std::ref(i));
i = 20;
f1();
f2();
}
Cet extrait génère:
10
20
La valeur de i
a été enregistrée (prise par valeur) dans f1
Au moment de son initialisation, mais f2
A conservé un std::reference_wrapper
Par valeur, et se comporte donc comme s'il prenait un int&
.
Une référence (T&
Ou T&&
) Est un élément spécial du langage C++. Il permet de manipuler un objet par référence et a des cas d'utilisation spéciaux dans la langue. Par exemple, vous ne pouvez pas créer de conteneur standard contenant des références: vector<T&>
Est mal formé et génère une erreur de compilation.
Un std::reference_wrapper
, Par contre, est un objet C++ capable de contenir une référence. En tant que tel, vous pouvez l'utiliser dans des conteneurs standard.
std::ref
Est une fonction standard qui renvoie un std::reference_wrapper
Sur son argument. Dans la même idée, std::cref
Renvoie std::reference_wrapper
À une référence const.
Une propriété intéressante d'un std::reference_wrapper
, Est qu'il a un operator T& () const noexcept;
. Cela signifie que même s'il s'agit d'un objet vrai, il peut être automatiquement converti en la référence qu'il détient. Alors:
operator T& () const noexcept;
, il peut être utilisé partout où vous pourriez utiliser une référence, car il sera automatiquement converti en cette référence.