Reputation: 449
After years of AS3, I'm trying to relearn C++. References are still giving me fits.
Consider the following functions:
#include <cstdio>
#include <list>
void f(std::list<int>& v) {
for (std::list<int>::iterator i = v.begin(); i != v.end(); ++i)
printf("Hello %d\n", *i);
}
std::list<int> get(void) {
std::list<int> list;
list.push_back(0);
return list;
}
Now, doing the following:
std::list<int> l = get();
f(l);
is fine, but f(get())
will produce the following error:
"no matching function for call to 'f'", "candidate function not viable: no known conversion from `'std::list<int>' to 'std::list<int>&' for 1st argument"
Why is that? Is it because the result of a function is invisibly const
?
Upvotes: 5
Views: 219
Reputation: 4335
You're returning a temporary std::list
variable from the get()
method. This doesn't work because your argument is not const
to function f
.
Upvotes: 0
Reputation: 17223
That's because your argument is T&. It it was T cont&, it worked fine.
Some old compilers made your version work as extension -- the rule is somewhat arbitrary, and is there to avoid surprise. T& arg means OUT (or INOUT) type, and if modifications end up in a temporary, it is a surprise.
Upvotes: -1
Reputation: 227578
When you do this:
f(get());
you pass a temporary std::list<int>
to f()
. A temporary cannot bind to a non-const reference. So you can fix this by passing a const
reference, since you do not want to modify the argument.
void f(const std::list<int>& v)
{ // ^^^^^
for (std::list<int>::const_iterator i = v.begin(); i != v.end(); ++i)
{ // ^^^^^^^^^^^^^^
printf("Hello %d\n", *i);
}
}
Note that this requires that you use a const_iterator
, since std::list::begin() const
and the corresponding end()
method return const_iterator
s. In C++11 you can simplify this to
for (auto i = v.begin(); i != v.end(); ++i)
...
or even
for (const auto& i : v)
std::cout << i << "\n";
Upvotes: 8