C++ Difference between std::ref(T) and T&? - c++

I have some questions regarding this program:
#include <iostream>
#include <type_traits>
#include <functional>
using namespace std;
template <typename T> void foo ( T x )
{
auto r=ref(x);
cout<<boolalpha;
cout<<is_same<T&,decltype(r)>::value;
}
int main()
{
int x=5;
foo (x);
return 0;
}
The output is:
false
I want to know, if std::ref doesn't return the reference of an object, then what does it do? Basically, what is the difference between:
T x;
auto r = ref(x);
and
T x;
T &y = x;
Also, I want to know why does this difference exist? Why do we need std::ref or std::reference_wrapper when we have references (i.e. 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 (here r) can be used to create an array of references which was not possible with T&.
r actually acts like a real reference (see how r.get()=70 changed the value of y).
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.

std::reference_wrapper is recognized by standard facilities to be able to pass objects by reference in pass-by-value contexts.
For example, std::bind can take in the std::ref() to something, transmit it by value, and unpacks it back into a reference later on.
void print(int i) {
std::cout << i << '\n';
}
int main() {
int i = 10;
auto f1 = std::bind(print, i);
auto f2 = std::bind(print, std::ref(i));
i = 20;
f1();
f2();
}
This snippet outputs :
10
20
The value of i has been stored (taken by value) into f1 at the point it was initialized, but f2 has kept an std::reference_wrapper by value, and thus behaves like it took in an int&.

A reference (T& or T&&) is a special element in C++ language. It allows to manipulate an object by reference and has special use cases in the language. For example, you cannot create a standard container to hold references: vector<T&> is ill formed and generates a compilation error.
A std::reference_wrapper on the other hand is a C++ object able to hold a reference. As such, you can use it in standard containers.
std::ref is a standard function that returns a std::reference_wrapper on its argument. In the same idea, std::cref returns std::reference_wrapper to a const reference.
One interesting property of a std::reference_wrapper, is that it has an operator T& () const noexcept;. That means that even if it is a true object, it can be automatically converted to the reference that it is holding. So:
as it is a copy assignable object, it can be used in containers or in other cases where references are not allowed
thanks to its operator T& () const noexcept;, it can be used anywhere you could use a reference, because it will be automatically converted to it.

Added an example to show the difference in value you get when you pass the T& and ref(T) arguments in the bind function.
std::bind copies the argument provided unless it is passed by std::ref()/std::cref().
void f(int r1, int& r2, int w1, int& w2)
{
std::cout << r1 << r2 << w1 << w2; // 5 5 10 10
r1 = 9, r2 = 9, w1 = 9, w2 = 9;
}
int main()
{
int w1 = 5, w2 = 5, n1 = 5, n2 = 5;
int& r1 = n1;
int& r2 = n2;
std::function<void()> bound_f = std::bind(f, r1, r2, std::ref(w1), std::ref(w2));
r1 = 10, r2 = 10, w1 = 10, w2 = 10;
bound_f(); // 5 5 10 10
std::cout << r1 << r2 << w1 << w2; // 10 10 10 9
}

Related

Is it possible to store a reference in a std::any?

I was trying some things and came to the following question: Is there a possibility to store references to a value in a std::any?
I tried the following approaches:
#include <any>
#include <iostream>
#include <functional>
auto func_by_pointer(std::any obj)
{
*std::any_cast<int *>(obj) += 2;
}
auto modify_by_pointer(int &a)
{
func_by_pointer(std::make_any<int *>(&a));
}
auto func_by_reference_wrapper(std::any obj)
{
std::any_cast<std::reference_wrapper<int>>(obj).get() -= 2;
}
auto modify_by_reference_wrapper(int &a)
{
func_by_reference_wrapper(std::make_any<std::reference_wrapper<int>>(a));
}
auto func_by_reference(std::any obj)
{
std::any_cast<int &>(obj) *= 2;
}
auto modify_by_reference(int &a)
{
func_by_reference(std::make_any<int &>(a));
}
int main()
{
auto value = 3;
std::cout << value << '\n';
modify_by_pointer(value);
std::cout << value << '\n';
modify_by_reference_wrapper(value);
std::cout << value << '\n';
modify_by_reference(value);
std::cout << value << '\n';
}
The result is the following output:
3
5
3
3
Yet, I was expecting it to be:
3
5
3
6
Thus, passing a pointer to value works fine. Passing a std::reference_wrapper to value works fine as well, but passing int& somehow doesn't work. Did I do something wrong in my code, or is it generally not possible to store references inside a std::any?
You cannot store references in std::any because, for a given type T, the constructor std::any(T) stores a value of type std::decay_t<T>, which removes reference qualifiers:
[any.cons]
template<class T>
any(T&& value);
Let VT be decay_­t<T>.
Requires: VT shall satisfy the Cpp17CopyConstructible requirements.
Effects: Constructs an object of type any that contains an object of type VT direct-initialized with std::forward<T>(value).

Rvalues, Lvalues and references confusion

I've been trying to understand rvalues, lvalues and references and their usage as a returning values of functions (methods) so i created few small examples for practice purpose.
So firstly, i came up with this code (after reading somewhere, possibly here, that whenever i have a "regular" (without reference) return value for some method, it is considered to be rvalue, exception is when i add reference operator sign in the return value, like in this example:
#include <iostream>
int x = 5;
int& References()
{
return x;
}
int main()
{
References() = 3;
std::cout << x;
getchar();
getchar();
}
So here, function References returns lvalue when called, and this code works out just fine, however, since this works, i thought that i can do something similar other way around, and this is what i tried:
#include <iostream>
int x = 5;
int References()
{
return x;
}
int main()
{
int a = References();
std::cout << a;
getchar();
getchar();
}
This code works just fine, the output is 5, which means that i successfully assigned value to the variable a, which is something i expected since this function returns "ordinary" integer so it a rvalue.
HOWEVER,
when i once again add reference operator sign to the return value of function References, again, it works fine:
#include <iostream>
int x = 5;
int& References()
{
return x;
}
int main()
{
int a = References();
std::cout << a;
getchar();
getchar();
}
So, even though my function now returns int& which is returned as lvalue, this code still works and the output is still 5, which means that i managed to assign the value to my variable a successfully. What is going on here? Any help appreciated!
When you return by reference you have an lvalue, when you return by value you have a prvalue. In your case the difference you can read from both of them, but cannot assign to prvalue, not clear where is your confusion coming from:
int i1 = lvalue; // fine
int i2 = prvalue; // fine
but:
lvalue = 123; // fine
prvalue = 123; // error
closer to your case:
int &func1();
int func2();
int i1 = func1(); // fine
int i2 = func2(); // fine
func1() = 123; // fine
func2() = 123; // error
more info: Value Category
When you use a reference in an expression or an assignment, it evaluates out to what the reference refers to, not the memory address, which I suppose is what you expect to see.
Compare the output of the following functions:
int x = 5;
int& Reference()
{
return x;
}
int *Pointer()
{
return &x;
}
int main()
{
std::cout << Reference() << std::endl;
std::cout << Pointer() << std::endl;
return 0;
}
According to https://learn.microsoft.com/en-us/previous-versions/f90831hc(v=vs.140) :
You can think of an lvalue as an object that has a name. All variables, including nonmodifiable (const) variables, are lvalues. An rvalue is a temporary value that does not persist beyond the expression that uses it.
The third example is exactly the same as the second one, it's copying the value. You can copy a value from an lvalue just how you can copy a value from an rvalue. If your a variable was of type int& instead, you wouldn't be copying the actual value, you'd just get the same reference. This might help you understand:
#include <iostream>
int x = 5;
int& References()
{
return x;
}
int main()
{
int a = References();
int& b = References();
std::cout << a; // 5
std::cout << b; // 5
std::cout << x; // 5
a = 6;
b = 7;
std::cout << a; // 6
std::cout << b; // 7
std::cout << b; // 7
getchar();
getchar();
}
For comparison:
int n = 10;
int& r = n;
int* p = &n;
int x = n; // copy by value
int y = r; // copy by value, too, use the variable referenced as source
int z = *p; // copy by value third time, using variable pointed to
int& r0 = r; // copy the reference, i. e. r0 now references n as well
int* p0 = p; // copy the pointer...
n = 12;
// now x, y, z all STILL have value 10!
// r, r0, *p and *p0, in contrast, all yield 12
Not different with functions:
int& ref() { return n; }
int val() { return n; }
int& r1 = ref(); // copy the reference, again r1 references n!
int& r2 = val(); // INVALID!!!
// the latter is comparable to:
int& r3 = 7; // invalid...

How to include arguments in a function pointer?

How can I include arguments in a function pointer?
This code creates a function pointer that can add two ints:
int addInt(int n, int m) {
return n+m;
}
int (*functionPtr)(int,int);
functionPtr = addInt;
(*functionPtr)(3,5); // = 8
For instance, I want to make a function pointer where the first argument is always 5, so that the function takes one int and adds five. And another one where the first argument is 8.
Is this possible using addInt? Something like:
// make-believe code that of course won't work
int (*functionPtr)(int);
functionPtr = addInt(5);
(*functionPtr)(3); // = 8
(*functionPtr)(9); // = 14
Use std::bind like this:
using namespace std::placeholders;
auto f = std::bind(addInt, 5, _1);
f(1); //returns 6
Use std::bind and placeholders
#include <iostream>
#include <functional>
using namespace std;
int addInt(int n, int m) {
return n+m;
}
int main() {
int (*functionPtr)(int,int);
functionPtr = addInt;
(*functionPtr)(3,5); // = 8
auto f2 = std::bind( addInt, std::placeholders::_1, 5);
auto f3 = std::bind( addInt, 8, std::placeholders::_1);
std::cout << f2(1) << "\n";;
std::cout << f3(1) << "\n";;
}
Output:
6
9
What you really want is a closure (you might also want curryfication, but C++ don't have that; consider switching to Ocaml if you really want it).
C+14 and C++11 have closures (but not earlier versions of C++). Read about C++ lambda functions (or anonymous functions) and the standard <functional> header and its std::function template.
Here is the function which given some integer d returns the translation by d i.e. the function taking an integer x and returning x+d
#include <functional>
std::function<int(int)> translation(int d) {
return [=](int x) { return addInt(x,d) /* or x+d */ ; };
}
Notice that std::function-s are not just C function pointers. They also contain closed values (d in my translation example)
The auto and decltype specifiers are tremendously useful.
For example:
auto addfive = translation(5);
std::cout << addfive(3) << std::end; // should output 8

When using bind(), arguments are passed by reference even if ref() adaptor is not used

I have the following C++11 code:
#include <iostream>
#include <functional>
using namespace std;
using namespace placeholders;
void f(int a, int b)
{
cout << a << " " << b << endl;
}
void g(int& a, int& b)
{
a *= 2;
b *= 3;
}
int main()
{
int a = 100;
int b = 200;
auto greversed = bind(g,_2,_1);
greversed(b,a);
f(a,b);
greversed(ref(b),ref(a));
f(a,b);
}
Based on my reading of "The C++ Programming Language 4th Edition" (Stroustrup) p. 968 I would expect that during the first call to greversed(b,a) that a copy of a and b would be passed by reference to g() and that only the second call would actually pass a and b to g() by reference.
The example code given on p. 968:
void incr(int& i)
{
++i;
}
void user()
{
int i =1;
incr(i); // i becomes 2
auto inc = bind(incr,_1);
inc(i); // i stays 2; inc(i) incremented a local copy of i
}
Running this code, i is incremented twice, despite what the comments say.
For my program, my expected output would be:
100 200
200 600
However, when I compile this code under Ubuntu using "g++ -std=c++11 test.cpp" I get the following output:
200 600
400 1800
It appears a and b are passed by reference no matter if the ref() adaptor are used or not.
Introduction
std::placeholders::_* works by perfectly-forwarding the types which later takes their place.
This mean that since you are passing a and b (which are lvalues) to greversed these lvalues will be forwarded to g, exactly like they are.
This behavior is explained in section [func.bind.bind]p10 of the Standard (n3337), but a more easy to understand explanation can be found here:
cppreference.com - std::bind
Source of confusion
I haven't read the book you are referring to, but your confusion probably lies in the fact that std::bind will not bind a reference to the passed in argument when you use a non-placeholder, instead it will copy the argument.
This below example hopefully aids in understanding the difference between using a std::placeholder, and passing in a value to be bound.
int main () {
auto f = [](int& r1, int& r2) {
r1 *= 2;
r2 *= 2;
};
int a = 1;
int b = 2;
auto x = std::bind (f, a, std::placeholders::_1); // a copy of `a` will be stored
// inside `x`
x (b); // pass the copy of `a`, and perfectly-forward `b`, to `f`
std::cout << "a: " << a << std::endl;
std::cout << "b: " << b << std::endl;
}
a: 1
b: 4

std::bind of class member function

I have this code:
#include <iostream>
#include <functional>
struct Foo
{
int get(int n) { return 5+n; }
};
int main()
{
Foo foo;
auto L = std::bind(&Foo::get, &foo, 3);
std::cout << L() << std::endl;
return 0;
}
Seems that this:
auto L = std::bind(&Foo::get, &foo, 3);
is equivalento to:
auto L = std::bind(&Foo::get, foo, 3);
Why?
std::bind() accepts its arguments by value. This means that in the first case you are passing a pointer by value, resulting in the copy of a pointer. In the second case, you are passing an object of type foo by value, resulting in a copy of an object of type Foo.
As a consequence, in the second case the evaluation of the expression L() causes the member function get() to be invoked on a copy of the original object foo, which may or may not be what you want.
This example illustrates the difference (forget the violation of the Rule of Three/Rule of Five, this is just for illustration purposes):
#include <iostream>
#include <functional>
struct Foo
{
int _x;
Foo(int x) : _x(x) { }
Foo(Foo const& f) : _x(f._x)
{
std::cout << "Foo(Foo const&)" << std::endl;
}
int get(int n) { return _x + n; }
};
int main()
{
Foo foo1(42);
std::cout << "=== FIRST CALL ===" << std::endl;
auto L1 = std::bind(&Foo::get, foo1, 3);
foo1._x = 1729;
std::cout << L1() << std::endl; // Prints 45
Foo foo2(42);
std::cout << "=== SECOND CALL ===" << std::endl;
auto L2 = std::bind(&Foo::get, &foo2, 3);
foo2._x = 1729;
std::cout << L2() << std::endl; // Prints 1732
}
Live example.
If, for any reason, you don't want to use the pointer form, you can use std::ref() to prevent a copy of the argument from being created:
auto L = std::bind(&Foo::get, std::ref(foo), 3);
They are not the same. The generic function binder std::bind copies it's arguments. In the case of std::bind(&Foo::get,&foo,3), the pointer is copied, but when you call the bound object it still applies to the original foo object. In std::bind(&Foo::get,foo,3) the object foo is copied, and the later call applies to the bound copy, not to the original object.
You can test this by using a member function that accesses internal state of the object, bind the object in both ways, change the original object and see how the results differ.