the standard (at least a working draft) already gives you hints about what is happening and how to solve it:
The return type is the lambda auto , which is replaced by the type indicated by the trailing-return-type if it is specified and / or deduced from the return statements, as described in [dcl.spec.auto]. [Example:
auto x1 = [](int i){ return i; }; // OK: return type is int auto x2 = []{ return { 1, 2 }; }; // error: deducing return type from braced-init-list int j; auto x3 = []()->auto&& { return j; }; // OK: return type is int&
- end of example]
Now consider the following template function:
template<typename T> void f(T t) {}
What is t in f , a copy of x or a link to it?
What happens if we change the function as it should?
template<typename T> void f(T &t) {}
The same applies to the inferred lambda return type more or less: if you want a link, you should be frank about it.
Why was this decision made? It seems to me that getcha removes the link when the returned statement is returned.
The choice is consistent with how the templates work from the start.
Instead, I would be surprised at the opposite. The type of the return value is displayed, as well as the template parameter, and a pretty good decision not to define different rules for them (at least from my point of view).
However, to solve your problem, you have several alternatives:
[&c]()->auto&&{ return c.getObj(); }
[&c]()->auto&{ return c.getObj(); }
[&c]()->decltype(c.getObj())&{ return c.getObj(); }
[&c]()->decltype(c.getObj())&&{ return c.getObj(); }
[&c]()->decltype(auto){ return c.getObj(); }
[&c]()->const Int &{ return c.getObj(); }
...
Some of them are crazy, some of them are completely clear, they should all work.
If the intended behavior is to return the link, perhaps to be explicit, this is the best choice:
[&c]()->auto&{ return c.getObj(); }
In any case, it is mostly opinion-based, so feel free to choose your preferred alternative and use it.
Interestingly, even if the output of type auto return makes sense, is it not an error that std :: function is successfully launched using a function that returns a link without a link?
Consider the code below (there is no reason to call std::function right now):
int f() { return 0; } const int & g() { return f(); } int main() { const int &x = g(); }
It gives you some warnings, but compiles.
The reason is that the temporary is created from rvalue, and the temporary can be associated with a constant reference, so I would say that this is legal from the point of view of the standard.
The fact that it explodes at runtime is another problem.
Something similar happens when using std:: function .
In any case, this is an abstraction over the common object being called, so don't expect the same warnings.