Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to correctly use std::reference_wrappers

I am trying to understand std::reference_wrapper.

The following code shows that the reference wrapper does not behave exactly like a reference.

#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; } 

If I understand it correctly, the implicit conversion does not apply to calling member functions. Is this an inherent limitation? Do I need to use the std::reference_wrapper::get so often?

Another case is this:

#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; } 

This works fine, but when I add this above the main definition:

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

The compiler tries to instantiate the template and forgets about implicit conversion and the built in operator.

Is this behavior inherent or am I misunderstanding something crucial about the std::reference_wrapper?

like image 666
Martin Drozdik Avatar asked Aug 08 '13 13:08

Martin Drozdik


People also ask

What is the use of reference_wrapper?

A reference_wrapper<Ty> is a copy constructible and copy assignable wrapper around a reference to an object or a function of type Ty , and holds a pointer that points to an object of that type. A reference_wrapper can be used to store references in standard containers, and to pass objects by reference to std::bind .

What is std :: reference_wrapper?

std::reference_wrapper is a class template that wraps a reference in a copyable, assignable object. It is frequently used as a mechanism to store references inside standard containers (like std::vector) which cannot normally hold references.

Can STD pair hold reference?

No, you cannot do this reliably in C++03, because the constructor of pair takes references to T , and creating a reference to a reference is not legal in C++03.


1 Answers

Class std::reference_wrapper<T> implements an implicit converting operator to T&:

operator T& () const noexcept; 

and a more explicit getter:

T& get() const noexcept; 

The implicit operator is called when a T (or T&) is required. For instance

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. 

However, sometimes a T is not necessarily expected and, in this case, you must use get. This happens, mostly, in automatic type deduction contexts. For instance,

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> 

To get some_type instead of std::reference_wrapper<some_type> above you should do

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

Alternativelly the last line above could be replaced by g<some_type>(x);. However, for templatized operators (e.g. ostream::operator <<()) I believe you can't explicit the type.

like image 117
Cassio Neri Avatar answered Oct 09 '22 13:10

Cassio Neri