0

The following line gives error in c++ 11:

function<bool(string,string)> comp = [] (string& s1, string& s2) {return s1.length() > s2.length(); };

but this does not:

function<bool(string,string)> comp = [] (const string& s1, const string& s2) {return s1.length() > s2.length(); };

The second call has const in parameters. Any explanation?

saha
  • 97
  • 8
  • 1
    Temporary objects or literals can't be bound to references to non-constant objects. [Any good beginners book](https://stackoverflow.com/a/388282/440558) should have told you so. โ€“ Some programmer dude Jan 28 '18 at 18:28
  • 2
    rvalues (such as parameters passed by value) cannot bind to non-const lvalue references, but can bind to const lvalue references. โ€“ Igor Tandetnik Jan 28 '18 at 18:28
  • 1
    You know auto works for lambda? `auto comp = ...` โ€“  Jan 28 '18 at 19:05

3 Answers3

1

It doesn't really have anything to do with lambdas. When you declare a function as taking a const reference, you activate lifetime extension.

void foo(const std::string& ref){ . . . }
void bar(std::string& ref){ . . . }

foo(std::string("hello")); 

Is allowed - the lifetime of the string containing hello is extended throughout the exection of foo.

For non-const references, there is no such extension rule, so the compiler will not allow:

bar(std::string("farewell")); 

because if it did, at the point foo starts, it would only have a reference to the destructed remnants of what was once the farewell string.

Johan Lundberg
  • 26,184
  • 12
  • 71
  • 97
1

From C++11 Standard ยง 20.8.11.2:

template<class R, class... ArgTypes>
class function<R(ArgTypes...)> { /* ... */ };

template<class F> function(F f);

Requires: f shall be Callable for argument types ArgTypes and return type R.

In your first case, Callable means that

INVOKE(f, declval<string>(), declval<string>(), bool)

is well formed, where f is lambda and declval represents rvalue objects of type string. Since rvalues cannot be bound to non-const lvalue references, this condition is not satisfied here.

On the contrary, rvalues can be bound to const lvalue references, thus the second case is ok.

Community
  • 1
  • 1
Daniel Langr
  • 22,196
  • 3
  • 50
  • 93
0

In your first case,

function<bool(string,string)> comp = [] (string& s1, string& s2) {return s1.length() > s2.length(); };

you are trying to compile something like this:

bool comp(string& s1, string& s2){/*...*/}
comp(string(), string());//passing a lvalue reference to a rvalue 

The error here is you are trying to get a non-const lvalue reference to a rvalue, that's a violation of standard.

Fixing solution 1, using function<bool(string &, string &)>(I think you probably trying to using this version):

function<bool(string&,string&)> comp = [] (string& s1, string& s2) {return s1.length() > s2.length(); };

Fixing solution 2, using rvalue reference:

function<bool(string,string)> comp = [] (string&& s1, string&& s2) {return s1.length() > s2.length(); };

In your second case,

function<bool(string,string)> comp = [] (const string& s1, const string& s2) {return s1.length() > s2.length(); };

you are trying to get a const lvalue reference to a rvalue, and this violates nothing of standard.

Francis
  • 737
  • 1
  • 7
  • 21