As usual, code first:
#include <functional>
using namespace std;
using namespace std::tr1;
void f(int& r) { r++; }
template<class F, class P> void g1(F f, P t) { f(t); }
template<class F, class P> void g2(F f, P&& t) { f(forward<P>(t)); }
int main()
{
int i = 0;
g1(f, ref(i)); // old way, ugly way
g2(f, i); // new way, elegant way
}
In C++ 98, we don't have a nice way to pefect forward parameters through template functions. So the C++ gurus invented ref and cref to achieve that aim.
Now that we have had r-value reference and perfect forwarding, does it mean that ref and cref and the like should be deprecated?
Reference wrappers are still useful. This is the case when it's about storing things. For example, with reference wrappers you can make std::make_tuple and std::thread create objects which refer to some argument instead of copying them:
class abstract_job
{
public:
virtual ~abstract_job() {}
virtual void run() = 0;
};
class thread
{
public:
template<class Fun, class... Args>
thread(Fun&& f, Args&&... args)
{
typedef typename decay<Fun>::type fun_type;
typedef decltype( make_tuple(forward<Args>(args)...) ) tuple_type;
unique_ptr<abstract_job> ptr (new my_job<fun_type,tuple_type>(
forward<Fun>(fun),
make_tuple(forward<Args>(args)...)
));
// somehow pass pointer 'ptr' to the new thread
// which is supposed to invoke ptr->run();
}
...
};
...
void foo(const int&);
int main()
{
thread t (foo, 42); // 42 is copied and foo is invoked
t.join() // with a reference to this copy
int i = 23;
thread z (foo, std::cref(i)); // foo will get a reference to i
z.join();
}
Keep in mind that
make_tuple(std::ref(i)) // yields a tuple<int&>
make_tuple( i ) // yields a tuple<int>
Cheers! s
That's assuming reference_wrapper
was intended for that. Rather it seems to be mostly about allowing passing function objects by reference where they would be normally taken by value. - If you were to take arguments as T&&
instead, wouldn't that mean that passing things by value becomes impossible?
#include <iostream>
#include <functional>
#include <algorithm>
class X: public std::unary_function<int, void>
{
int n;
public:
X(): n(0) {}
void operator()(int m) {n += m;}
int get_n() const { return n; }
};
template <class Iter, class Fun>
void for_each(Iter from, Iter to, Fun&& fun)
{
for (; from != to; ++from)
fun(*from);
}
int main()
{
int a[] = {1, 2, 3};
X x1;
::for_each(a, a + 3, x1);
std::cout << x1.get_n() << '\n'; //6
X x2;
std::for_each(a, a + 3, x2);
std::cout << x2.get_n() << '\n'; //0
X x3;
std::for_each(a, a + 3, std::ref(x3));
std::cout << x3.get_n() << '\n'; //6
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With