The example on the page of std::ref/std::cref shows the use of std::ref/std::cref to pass arguments to std::bind in a way that looks like std::bind is taking arguments by reference, when in reality it takes them all by value.
Looking at that example only, I could also be ignorant about the existence of std::reference_wrapper, and std::ref would just be a function that allows the behavior exhibited by the linked example.
That's what I mean by std::ref works in the title of the question and also in the following.
Mostly for fun I've tried implementing std::ref myself, and I came up with this:
template<typename T>
struct ref_wrapper {
ref_wrapper(T& t) : ref(t) {}
T& ref;
operator T&() const {
return ref;
}
};
template<typename T>
ref_wrapper<T> ref(T& t) {
return ref_wrapper{t}; // Ooops
}
template<typename T>
ref_wrapper<const T> cref(const T& t) {
return ref_wrapper{t}; // Ooops
}
where on the lines marked as // Ooops I have mistakely made use of CTAD because I was compiling with -std=c++17. By changing ref_wrapper to ref_wrapper<T> and ref_wrapper<const T> in the two cases corrects this.
Then I've had a peek into /usr/include/c++/10.2.0/bits/refwrap.h.
On the one hand, I see that my implementation of ref/cref closely resembles that of std::ref/std::cref.
On the other hand, I see that std::reference_wrapper is around 60 lines long! There's a lot of stuff in there, including noexcept, macros, copy ctor, copy operator=, get.
I think most of that is not relevant to the use of std::reference_wrapper only as a slave to std::ref, but there's something which could be relevant, such as constructor taking a universal reference.
So my question is: what are the parts of std::reference_wrapper necessary and sufficients for std::ref to work, with respect to my skinny attempt?
I've just realized that there's a possible implementation of std::reference_wrapper on cppreference (which is less noisy than the one from GCC). Even here, however, there are things I don't undertand the reason of, such as operator().
The logic that you're talking about is implemented entirely within
std::binditself. The main functionality it needs fromstd::reference_wrapperis the fact that it can be "unwrapped" (i.e., you can call.get()on it in order to retrieve the underlying reference). When the call wrapper (i.e. object returned fromstd::bind) is called, it simply checks whether any of its bound arguments is astd::reference_wrapper. If so, it calls.get()to unwrap it, then passes the result to the bound callable.std::bindis complicated because it is required to support various special cases, such as recursivebinding (this feature is now considered a design mistake), so instead of trying to show how to implement the fullstd::bind, I'll show a custombindtemplate that's sufficient for the example on cppreference:The idea is that
bindsaves its own copy of the callable and each of the args. If an argument is areference_wrapper, thereference_wrapperitself will be copied, not the referent. But when the call wrapper is actually invoked, it unwraps any saved reference wrapper argument. The code to do this is simple:That is, arguments that are not
reference_wrappers are simply passed through, whilereference_wrappers go through the second, more specialized overload.The
reference_wrapperitself merely needs to have a relevant constructor andget()method:The
refandcreffunctions are easy to implement. They just call the constructor, having deduced the type:You can see the full example on Coliru.
(The actual constructor of
std::reference_wrapper, as shown on cppreference, is complicated because it needs to satisfy the requirement that the constructor will be SFINAE-disabled if the argument would match an rvalue reference better than an lvalue reference. For the purposes of your question, it doesn't seem necessary to elaborate on this detail further.)