How Is Tr1::Reference_Wrapper Useful

How is tr1::reference_wrapper useful?

It's like boost::ref, as far as I know. Basically, a reference which can be copied. Very useful when binding to functions where you need to pass parameters by reference.

For example (using boost syntax):

void Increment( int& iValue )
{
iValue++;
}

int iVariable = 0;
boost::function< void () > fIncrementMyVariable = boost::bind( &Increment, boost::ref( iVariable ));

fIncrementMyVariable();

This Dr. Dobbs article has some info.

Hope this is right, and helpful. :)

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:

  1. A reference_wrapper object (here r) can be used to create an array of references which was not possible with T&.

  2. r actually acts like a real reference (see how r.get()=70 changed the value of y).

  3. r is not same as T& but r.get() is. This means that r holds T& ie as its name suggests is a wrapper around a reference T&.

I hope this answer is more than enough to explain your doubts.

confusion between std::[tr1::]ref and boost::ref

Define a version of boost::ref() specifically taking a boost::any and have it return the proper type. Probably

namespace boost {
std::tr1::reference_wrapper<boost::any const>
ref(boost::any const& o) {
return std::tr1::ref(o);
}
}

Problem replacing boost::bind with std::tr1::bind

This appears to be a difference in how bind is implemented in MS Visual Studio (including 2010) and GNU gcc (I tested 4.4.1 and 4.5.2, both of which work the way you expected)

Consider the following code, given your definitions

auto b = boost::bind(&MenuItem);
NoncopyableObject obj(7);
b(obj); // OK in VS and GCC

replacing boost::bind with std::bind (I'm using 2010, the error message appears to be the same as in your 2008)

auto b = std::bind(&MenuItem);
NoncopyableObject obj(7);
b(obj); // compile error in VS 2010 SP1, OK in GCC
b(std::reference_wrapper<NoncopyableObject>(obj)); // OK in both

So, what happens is that MS's bind() makes a copy of its argument even if the argument is not going to be used, while boost's and GCC's bind() does not bother with that argument at all.

I was able to get your example to compile and run (on 2010) by changing the FUNC typedef to

typedef boost::function1<void, std::tr1::reference_wrapper<NoncopyableObject> > FUNC;

Is passing a reference to a local variable in main() to other threads/functions bad practice?

Your assumption

I am aware that passing references to local variables around should generally be avoided

seems unfounded.

There is nothing wrong with passing references to functions. However, a function that takes a reference to an object should not take ownership of that object. The function should not assume that the referenced object continues to live after it exits.

This is different from returning references to local variables, which is always wrong.

I see no problem (missing synchronization aside) with passing references to threads and this generally preferable to the alternative of using global variables.

Smart pointers, such as std::shared_ptr, are only required if the functions are supposed to take (shared) ownership of the object, e.g. if threadRun wants to keep a reference/pointer to the object after it exits.

Why does my std::ref not work as expected?

The reason this does not work is because your wrapper function takes an int as argument.

std::ref returns a std::reference_wrapper.
When you pass it to a function that wants an int
you will get an implicit conversion and you arre no longer working with a reference.

If you change your function signature to use a std::reference_wrapper it will give the intended result.

#include <iostream>
#include <functional>

template<typename F>
auto wrapper(std::reference_wrapper<int> i, F func) {
return [=]() { return func(i); };
}

void f(int i) {
std::cout << "i is " << i << '\n';
}

int main() {
int tmp = 1;
auto func = wrapper(std::ref(tmp), f);
tmp = 2;
func();
}

std::pair of references

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.

Notice that I said "reliably". Some common compilers still in use (for GCC, I tested GCC4.1, @Charles reported GCC4.4.4) do not allow forming a reference to a reference, but more recently do allow it as they implement reference collapsing (T& is T if T is a reference type). If your code uses such things, you cannot rely on it to work on other compilers until you try it and see.

It sounds like you want to use boost::tuple<>

int a, b;

// on the fly
boost::tie(a, b) = std::make_pair(1, 2);

// as variable
boost::tuple<int&, int&> t = boost::tie(a, b);
t.get<0>() = 1;
t.get<1>() = 2;


Related Topics



Leave a reply



Submit