Daniel Kitachewsky
Daniel Kitachewsky

Reputation: 449

Result of function can't be passed as reference

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

Answers (3)

Tyler Jandreau
Tyler Jandreau

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

Balog Pal
Balog Pal

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

juanchopanza
juanchopanza

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

Related Questions