Reputation: 7719
Consider:
std::tuple<int , const A&> func (const A& a)
{
return std::make_tuple( 0 , std::ref(a) );
}
Is the std::ref
required for writing correct and portable code? (It compiles fine without it)
Background:
If I remove std::ref
my code builds fine without any warnings (g++-4.6 -Wall
), but doesn't run correctly.
In case of interest the definition of A
:
struct A {
std::array<int,2> vec;
typedef int type_t;
template<typename... OPs,typename... VALs>
A& operator=(const std::pair< std::tuple<VALs...> , std::tuple<OPs...> >& e) {
for( int i = 0 ; i < vec.size() ; ++i ) {
vec[i] = eval( extract(i,e.first) , e.second );
}
}
};
Upvotes: 53
Views: 52887
Reputation: 18695
Answering the question in the title (When is the use of std::ref necessary?
): Another case where std::ref
is useful is when looping over a list of references to objects and modify them:
std::vector<int> v1, v2;
void test() {
for (std::vector<int>& vv :
// Compiles
{ std::ref(v1), std::ref(v2) }
// Compiler rejects this with:
// binding reference of type 'vector<...>' to value of
// type 'const vector<...>' drops 'const' qualifier
// { v1, v2}
) {
vv.push_back(3);
}
}
Without using std::ref
in the list, the objects are treated as const
and can't be modified (see also https://godbolt.org/z/Ta6YM31KM).
Upvotes: 3
Reputation: 13954
One of the example where std::ref
is necessary:
void update(int &data) //expects a reference to int
{
data = 15;
}
int main()
{
int data = 10;
// This doesn't compile as the data value is copied when its reference is expected.
//std::thread t1(update, data);
std::thread t1(update, std::ref(data)); // works
t1.join();
return 0;
}
The std::thread
constructor copies the supplied values, without converting to the expected argument type (which is reference type in this case, seeupdate()
). So we need to wrap the arguments that really needs to be references in std::ref
.
Upvotes: 54
Reputation: 227468
std::ref
does not make a reference, so in your code sample it doesn't do what you expect. std::ref
creates an object that behaves similarly to a reference. It may be useful, for example, when you want to instantiate a functor, and pass a reference-like version of it to a standard library algorithm. Since algorithms take functors by value, you can use std::ref
to wrap the functor.
Upvotes: 28
Reputation: 477368
make_tuple(0, a)
makes a tuple<int, A>
.make_tuple(0, ref(a))
makes a tuple<int, reference_wrapper<A>>
.tuple<int, A&> t(0, a);
for a tuple you can't make with make_tuple
, or use std::tie
.Upvotes: 25