Is there a reference_wrapper for rvalue references?
My take on this.
20.8.10.1.2/10 in N3225
The values of the bound arguments v1, v2, ..., vN and their corresponding types V1, V2, ..., VN
depend on the types TiD derived from the call to bind and the cv-qualifiers cv of the call wrapper g as
follows:
- if TiD is reference_wrapper, the argument is tid.get() and its type Vi is T&;
- if the value of is_bind_expression::value is true, the argument is tid(std::forward(uj)...)
and its type Vi is result_of::type;- if the value j of is_placeholder::value is not zero, the argument is std::forward(uj)
and its type Vi is Uj&&;- otherwise, the value is tid and its type Vi is TiD cv &.
So the only possibility to have a rvalue reference is to have is_bind_expression<TiD>::value
true or is_placeholder<TiD>::value
not zero. The second possibility has implications you don't want and achieving the wanted result with the first would imply that the problem we are trying to solve is solved if we restrict to the standard provided types. So, the only possibility would be to provide your own wrapper and a specialisation for is_bind_expression<TiD>
(that is allowed by 20.8.10.1.1/1) as I don't see one.
Trying to wrap std containers to store rvalue references (like unique_ptr, but on the stack)
If you want to avoid copy elements around you can use std::move.
So if you have a std::list you can populate it with values by moving them in:
SomeBigObject sbo;
std::list<SomeBigObject> list;
list.push_back(SomeBigObject()); // SomeBigObject() is a rvalue and so it is moved
list.push_back(std::move(sbo)); // sbo may not be a rvalue so you have to move it
// For construction you can also use std::list::emplace
list.emplace(list.end()); // construct the value directly at the end of the list
For accessing them you can simply use the ranged based loop:
for(auto& i :list)
...
If you want to move them out of the container you can also use std::move.
The object is moved out of the container but the remains will still be in the container,
so you have to erase them:
for(auto it = list.begin; it != lsit.end();)
{
// the value of *it is moved into obj;
// an empty value of "SomeBigObject" will remain so erase it from the list
SomeBigObject obj = std::move(*it);
it = list.erase(it);
// do something with "obj"
...
}
rvalue references, std::reference_wrappers and std::function
That is because none of the objects you create actually is a std::function, they are callables which can be used to create temporary std::functions. And the last bit to the best of my knowledge (e.g. I'm not claiming it's true, I'm assuming that due to my laziness, see below) is UB, as moved from object can be left in any valid state, so no guarantees that the string member will actually be empty.
As a rule of thumb, use moved from objects in ways that don't require any preconditions (reassign, check if empty for string / vec, etc. qualify).
To clarify, let's look at the std::function constuctors here, the constructor in question is (5):
template< class F >
function( F f );
So when you try to construct an std::function with a callable, you by default will create a copy of the callable. You circumvent it e.g. by using std::ref, which will cause the subsequent changes to the callable to be reflected in the std::function using it (as then you actually create "from ref", not by from copy as usual).
What is the difference between std::reference_wrapper and a simple pointer?
std::reference_wrapper
is useful in combination with templates. It wraps an object by storing a pointer to it, allowing for reassignment and copy while mimicking its usual semantics. It also instructs certain library templates to store references instead of objects.
Consider the algorithms in the STL which copy functors: You can avoid that copy by simply passing a reference wrapper referring to the functor instead of the functor itself:
unsigned arr[10];
std::mt19937 myEngine;
std::generate_n( arr, 10, std::ref(myEngine) ); // Modifies myEngine's state
This works because…
…
reference_wrapper
s overloadoperator()
so they can be called just like the function objects they refer to:std::ref(myEngine)() // Valid expression, modifies myEngines state
…(un)like ordinary references, copying (and assigning)
reference_wrappers
just assigns the pointee.int i, j;
auto r = std::ref(i); // r refers to i
r = std::ref(j); // Okay; r refers to j
r = std::cref(j); // Error: Cannot bind reference_wrapper<int> to <const int>
Copying a reference wrapper is practically equivalent to copying a pointer, which is as cheap as it gets. All the function calls inherent in using it (e.g. the ones to operator()
) should be just inlined as they are one-liners.
reference_wrapper
s are created via std::ref
and std::cref
:
int i;
auto r = std::ref(i); // r is of type std::reference_wrapper<int>
auto r2 = std::cref(i); // r is of type std::reference_wrapper<const int>
The template argument specifies the type and cv-qualification of the object referred to; r2
refers to a const int
and will only yield a reference to const int
. Calls to reference wrappers with const
functors in them will only call const
member function operator()
s.
Rvalue initializers are disallowed, as permitting them would do more harm than good. Since rvalues would be moved anyway (and with guaranteed copy elision even that's avoided partly), we don't improve the semantics; we can introduce dangling pointers though, as a reference wrapper does not extend the pointee's lifetime.
Library interaction
As mentioned before, one can instruct make_tuple
to store a reference in the resulting tuple
by passing the corresponding argument through a reference_wrapper
:
int i;
auto t1 = std::make_tuple(i); // Copies i. Type of t1 is tuple<int>
auto t2 = std::make_tuple(std::ref(i)); // Saves a reference to i.
// Type of t2 is tuple<int&>
Note that this slightly differs from forward_as_tuple
: Here, rvalues as arguments are not allowed.
std::bind
shows the same behavior: It won't copy the argument but store a reference if it is a reference_wrapper
. Useful if that argument (or the functor!) need not be copied but stays in scope while the bind
-functor is used.
Difference from ordinary pointers
There is no additional level of syntactical indirection. Pointers have to be dereferenced to obtain an lvalue to the object they refer to;
reference_wrapper
s have an implicit conversion operator and can be called like the object they wrap.int i;
int& ref = std::ref(i); // Okayreference_wrapper
s, unlike pointers, don't have a null state. They have to be initialized with either a reference or anotherreference_wrapper
.std::reference_wrapper<int> r; // Invalid
A similarity are the shallow copy semantics: Pointers and
reference_wrapper
s can be reassigned.
C++ Difference between std::ref(T) and T&?
Well ref
constructs an object of the appropriate reference_wrapper
type to hold a reference to an object. Which means when you apply:
auto r = ref(x);
This returns a reference_wrapper
and not a direct reference to x
(ie T&
). This reference_wrapper
(ie r
) instead holds T&
.
A reference_wrapper
is very useful when you want to emulate a reference
of an object which can be copied (it is both copy-constructible and copy-assignable).
In C++, once you create a reference (say y
) to an object (say x
), then y
and x
share the same base address. Furthermore, y
cannot refer to any other object. Also you cannot create an array of references ie code like this will throw an error:
#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;
}
However this is legal:
#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
*/
Talking about your problem with cout << is_same<T&,decltype(r)>::value;
, the solution is:
cout << is_same<T&,decltype(r.get())>::value; // will yield true
Let me show you a program:
#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
*/
See here we get to know three things:
A
reference_wrapper
object (herer
) can be used to create an array of references which was not possible withT&
.r
actually acts like a real reference (see howr.get()=70
changed the value ofy
).r
is not same asT&
butr.get()
is. This means thatr
holdsT&
ie as its name suggests is a wrapper around a referenceT&
.
I hope this answer is more than enough to explain your doubts.
How can a std::reference_wrapper to a rvalue lambda work?
OK, let's start with the basics: the above code is certainly not legal because it is ill-formed in some rather basic ways. The line
std::function<bool(int)> f(std::cref([n](int i) {return i%n == 0));
would at bare minimum need to be written as
std::function<bool(int)> f(std::cref([n](int i) {return i%n == 0;}));
Note that the code was written in the Dr.Dobb's article as it was in the question, i.e., any statement of the code being legal is already quite questionable.
Once the simple syntax errors are resolved the next question is whether std::cref()
can actually be used to bind to an rvalue. The lambda exrpession is clearly a temporary according to 5.1.2 [expr.prim.lambda] paragraph 2 (thanks to DyP for the reference). Since it would generally be a rather bad idea to bind a reference to a temporary and is prohibited elsewhere, std::cref()
would be a way to circumvent this restriction. It turns out that according to 20.10 [function.objects] paragraph 2 std::cref()
is declared as
template <class T> reference_wrapper<const T> cref(const T&) noexcept;
template <class T> void cref(const T&&) = delete;
template <class T> reference_wrapper<const T> cref(reference_wrapper<T>) noexcept;
That is, the statement is incorrect even after correcting the syntax errors. Neither gcc nor clang compile this code (I have used fairly recent versions of both compilers with their respective standard C++ libraries). That is, based on the above declaration this code is clearly illegal!
Finally, there is nothing which would extend the life-time of the temporary in the above expression. The only reason the life-time of a temporary is extended is when it or one of its data members is immediately bound to a [const
] reference. Wrapping a function call around the temporary inhibits this life-time extensions.
In summary: the code quoted in the article is not legal on many different levels!
std::thread taking lambda with ref arg fails to compile
Another variation on the same theme that template argument deduction doesn't look through conversions.
The operator()
of f<int>
is
void operator() (int& result);
when you pass a reference_wrapper<int>
to it, the conversion function (operator int &
) is called, yielding a reference that can be bound to result
.
The operator()
of your generic lambda is
template<class T> void operator() (T& result) const;
If it were passed a reference_wrapper
lvalue, it would deduce T
as a reference_wrapper
and then fail to compile on the assignment. (Assignment to a reference_wrapper
reseats the "reference" rather than affects the value.)
But it fails even before that, because the standard requires that what you pass to std::thread
must be callable with prvalues - and a non-const lvalue reference doesn't bind to a prvalue. This is the error you see - result_of
contains no type
because your functor is not callable for the argument type. If you attempt to do g(std::ref(x));
, clang produces a rather clear error:
main.cpp:16:5: error: no matching function for call to object of type '(lambda at main.cpp:11:14)'
g(std::ref(x));
^
main.cpp:11:14: note: candidate function [with $auto-0-0 = std::__1::reference_wrapper<int>] not viable: expects an l-value for 1st argument
auto g = [](auto& result) { result = 1; };
^
You should probably consider just capturing the relevant local by reference:
auto g = [&x]() { x = 1; };
Or if, for whatever reason, you must use a generic lambda, then you might take a reference_wrapper
by value (or by const reference), and then unwrap it using get()
:
auto g = [](auto result) { result.get() = 1; };
or perhaps add a std::bind
which will unwrap the reference_wrapper
s, which lets template argument deduction do the right thing (hat tip @Casey):
std::thread(std::bind(g, std::ref(x)));
or perhaps dispense with this reference_wrapper
nonsense and write your lambda to take a non-owning pointer instead:
auto g = [](auto* result) { *result = 1; };
std::thread(g, &x);
Related Topics
How to Implement Timeout for Function in C++
Function to Mangle/Demangle Functions
If Temporaries Are Implicitly Non-Modifiable, How Does This Work
Does "Undefined Behaviour" Extend to Compile-Time
Using Std:Fstream How to Deny Access (Read and Write) to the File
C++ Overloaded Function as Template Argument
Can Raw Pointers Be Used Instead of Iterators with Stl Algorithms for Containers with Linear Storage
Why Is Locking a Std::Mutex Twice 'Undefined Behaviour'
Where Are the Man Pages for C++
How to Build Google's Protobuf in Windows Using Mingw
Using C Function from Other Package in Rcpp
Gcc - How to Create a Mapfile of the Object File
How to Create a Temporary Directory in C++