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

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).

Related

Did std::bind implement std::ref and std::cref to disambiguate the function call?

I know that I shouldn't overload a function for just parameters differ only in one of them passed by copy and the other by reference:
void foo(int x)
{
cout << "in foo(int x) x: " << x << endl;
}
void foo(int& x)
{
cout << "in foo(int& x) x: " << x << endl;
}
int main()
{
int a = 1;
foo(5); // ok as long as there is one best match foo(int)
foo(a); // error: two best candidates so the call is ambiguous
//foo(std::move(a));
//foo(std::ref(an)); // why also this doesn't work?
}
So a code that uses std::bind can be like this:
std::ostream& printVec(std::ostream& out, const std::vector<int> v)
{
for (auto i : v)
out << i << ", ";
return out;
}
int main()
{
//auto func = std::bind(std::cout, std::placeholders::_1); // error: stream objects cannot be passed by value
auto func = std::bind(std::ref(std::cout), std::placeholders::_1); // ok.
}
So std::ref here to ensure passing by reference rather than by value to avoid ambiguity?
* The thing that matters me: Does std::bind() implemented some wrapper to overcome this issue?
Why I can't use std::ref in my example to help the compiler in function matching?
Now that you know passing by value and reference are ambiguous when overload resolution tries to compare them for choosing a best viable function, let's answer how would you use std::ref (or std::cref) to differentiate between pass-by-value and pass-by-reference.
It turns out to be ... pretty simple. Just write the overloads such that one accepts a int, and the other accepts a std::reference_wrapper<int>:
#include <functional>
#include <iostream>
void foo(int x) {
std::cout << "Passed by value.\n";
}
void foo(std::reference_wrapper<int> x) {
std::cout << "Passed by reference.\n";
int& ref_x = x;
ref_x = 42;
/* Do whatever you want with ref_x. */
}
int main() {
int x = 0;
foo(x);
foo(std::ref(x));
std::cout << x << "\n";
return 0;
}
Output:
Passed by value.
Passed by reference.
42
The function pass the argument by value by default. If you want to pass by reference, use std::ref explicitly.
Now let's answer your second question: how does std::bind deal with this type of scenario. Here is a simple demo I have created:
#include <functional>
#include <type_traits>
#include <iostream>
template <typename T>
struct Storage {
T data;
};
template <typename T>
struct unwrap_reference {
using type = T;
};
template <typename T>
struct unwrap_reference<std::reference_wrapper<T>> {
using type = std::add_lvalue_reference_t<T>;
};
template <typename T>
using transform_to_storage_type = Storage<typename unwrap_reference<std::decay_t<T>>::type>;
template <typename T>
auto make_storage(T&& obj) -> transform_to_storage_type<T> {
return transform_to_storage_type<T> { std::forward<T>(obj) };
}
int main() {
int a = 0, b = 0, c = 0;
auto storage_a = make_storage(a);
auto storage_b = make_storage(std::ref(b));
auto storage_c = make_storage(std::cref(c));
storage_a.data = 42;
storage_b.data = 42;
// storage_c.data = 42; // Compile error: Cannot modify const.
// 0 42 0
std::cout << a << " " << b << " " << c << "\n";
return 0;
}
It is not std::bind, but the method used is similar (it's also similar to std::make_tuple, which has the same semantic). make_storage by default copies the parameter, unless you explicitly use std::ref.
As you can see, std::ref is not magic. You need to do something extra for it to work, which in our case is to first decay the type (all references are removed in this process), and then check whether the final type is a reference_wrapper or not; if it is, unwrap it.

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

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
}

vector push_back shows absurd result

I am trying to make a vector out of several integers by overloading the operator << and conversion operator.
However, when I test my code, I observe some absurd results.
The printed output should be 1 2 3 4.
But it actually print out something like this: 28495936 0 3 4.
The first two elements (e.g, 1 and 2) that were supposed to be pushed into the vector is lost or polluted.
I would appreciate it if someone can help me to figure it out the reason behind this.
#include <iostream>
#include <vector>
using namespace std;
template<typename T>
class make_vector {
public:
typedef make_vector<T> my_type;
my_type& operator<<(const T& val)
{
data_.push_back(val);
return *this;
}
operator std::vector<T>&()
{
return this->data_;
}
private:
std::vector<T> data_;
};
int main() {
std::vector<int>& A2 = make_vector<int>() << 1 << 2 << 3 << 4;
for (std::vector<int>::iterator it = A2.begin(); it != A2.end(); ++it)
{
cout << *it << " ";
}
cout << endl;
return 0;
}
You are binding a lvalue reference to a temporary:
std::vector<int>& A2 = make_vector<int>() << 1 << 2 << 3 << 4;
Note that, as #T.C. mentions in comments, it is your conversion operator that enables this. Without it the statement above would be invalid C++.
The issue with your code is that after this line, A2 refers to a defunct object.
It seems to me you don't want to use a reference:
std::vector<int> A2 = make_vector<int>() << 1 << 2 << 3 << 4;
You have a dangling reference here. It references a temporary.
std::vector<int>& A2 = make_vector<int>()....
You have two options:
You can copy the temp into a new, local variable.
std::vector<int> A2 = make_vector<int>()....
Or use a const ref. C++ grants a special rule to allow const references to extend the lifetime of a temporary.
const std::vector<int>& A2 = make_vector<int>()....
Your make_vector is badly designed and dangerous to use. You made it convertible to std::vector<T>& referring to its vector member, even if the make_vector object is a temporary. This is a dangling reference waiting to happen, since with this setup the compiler won't complain when you do things like
std::vector<int>& A2 = make_vector<int>() << 1 << 2 << 3 << 4;
because everything in this line is perfectly valid. Except that it leaves A2 a dangling reference as the make_vector temporary - and the vector it contains - gets destroyed at the ;. Ouch.
A better design would ref-qualify and overload your operator<< and the conversion function:
my_type& operator<<(const T& val) &
{
data_.push_back(val);
return *this;
}
my_type&& operator<<(const T& val) &&
{
data_.push_back(val);
return std::move(*this);
}
operator std::vector<T>&() &
{
return this->data_;
}
operator std::vector<T>() &&
{
return std::move(this->data_);
}
First, we make only lvalue make_vectors convertible to an lvalue reference to the underlying vector, since this is probably safe. For rvalue make_vectors, such as temporaries, we make the conversion function return the vector by value by moving from the underlying vector.
Second, we overload operator<< to preserve the value category of the make_vector object it is invoked on - it returns an lvalue reference if invoked on an lvalue, and an rvalue reference if invoked on an rvalue. This way, make_vector<int>() << 1 << 2 << 3 << 4 remains an rvalue.
Now errors like std::vector<int>& A2 = make_vector<int>() << 1 << 2 << 3 << 4; won't compile, while both
std::vector<int> A2 = make_vector<int>() << 1 << 2 << 3 << 4;
and
const std::vector<int> & A2 = make_vector<int>() << 1 << 2 << 3 << 4;
will and both are safe. (In the second case, the const reference binds to the temporary returned by operator std::vector<int>(), which extends the lifetime of the temporary.)

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.

function objects and constructors

I was just reading this
class biggerThan
{
public:
const int testValue;
biggerThan(int x) : testValue(x) { }
bool operator()(int val) const
{ return val > testValue; }
};
Now say its used like
std::list<int>::iterator firstBig =
std::find_if(aList.begin(), aList.end(), biggerThan(12));
OR
Just simply like this
biggerThan object(12)
Now when biggerThan(12) this is used it can invoke the constrcutor to initialze the testvalue or () operator is overloaded and 12 is passed to the function(bool operator()(int val) const ) so that it returns a bool.
which one happens first/how does it works
does it leads to any ambiguity or does the call to the overlaode operator happens in some fashion like
object.operator().(12).
please make my undersatnding clear.
Maybe the following code will make it clear:
#include <iostream>
#include <algorithm>
class biggerThan
{
public:
const int testValue;
biggerThan(int x) : testValue(x) {
std::cout << "Construction of biggerThan object with value "
<< x << std::endl;
}
bool operator()(int val) const
{
if (val > testValue) {
std::cout << val << " is bigger than " << testValue
<< std::endl;
return true;
}
else {
std::cout << val << " is *not* bigger than " << testValue
<< std::endl;
return false;
}
}
};
int main() {
int data[] = {0,1,2,3,4,5,6,7,8,9};
std::for_each(data, data+10, biggerThan(4));
}
The output is:
Construction of biggerThan object with value 4
0 is *not* bigger than 4
1 is *not* bigger than 4
2 is *not* bigger than 4
3 is *not* bigger than 4
4 is *not* bigger than 4
5 is bigger than 4
6 is bigger than 4
7 is bigger than 4
8 is bigger than 4
9 is bigger than 4
What happens:
The last argument to std::for_each is an object of type biggerThan, that is constructed with the argument 4.
The operator()(int) of this biggerThan-object (actually a copy of it) is invoked for every element in data.
The algorithm you use (std::find_if) works the same in this regard.
when biggerThan(12) this is used it can invoke the constructor to initialize the testvalue
Yes. biggerThan(12) creates an instance of the biggerThan class with testvalue set to 12.
When std::find_if() calls the functor, it will call the operator()(int val) member function of that instance.
biggerThan(12) will pass an object of biggerThan at std::find_if(aList.begin(), aList.end(), biggerThan(12)); line;
To invoke operator() following is the way;
biggerThan obj(12); //This is a constructor call
biggerThan(13); //This is function operator call
#std::find_if(aList.begin(), aList.end(), biggerThan(12)); the third parameter that is passed will be temporary object of biggerThan initialized with 12
In general, you can accomplish the same thing using greater<> and bind2nd<>, which are in <functional>
list<int>::iterator firstBig = find_if(aList.begin(), aList.end,
bind2nd(greater<int>(), 12));
bind2nd turns any binary function object, like greater<int> into a unary function object. In the case of greater<int> it effectively creates a function object whose less than operator looks like this
bool operator>(const int& arg)
{
return functor.operator>(arg, 12);
}
where functor is greater<int>