Lambda fct return link

I tried to make a lambda function by returning a value by reference, without making a copy of the reference value. My sample code below illustrates the problem. It compiles and starts normally, but using the comment line β€œ//” instead of the line above, it is not. I found two workarounds (both illustrated in my example):

  • completes the result with std :: ref ()
  • returns a pointer instead of a link

But the workarounds are not what I really want, and I don’t understand why they are needed: the expression "makeRefA ()" already has the type returned by the lambda function (const A &), and therefore it should not be copied, converted . By the way: the copy constructor is really called when I do not explicitly delete it (which is a performance issue in my "real" code). For me, this seems like a compiler error, but I tried with several C ++ 11 compilers that detect the same error. So, is there anything special about the "return" expression in a lambda function?

#include <functional> #include <iostream> struct A { A(int i) : m(i) { } A(const A&) = delete; int m; }; void foo(const A & a) { std::cout << am <<'\n'; } const A & makeRefA() { static A a(3); return a; } int main() { std::function<const A&()> fctRef = [&] { return std::ref(makeRefA()); }; //compiles ok //{ return makeRefA(); }; //error: use of deleted function 'A::A(const A&)' foo(fctRef()); std::function<const A*()> fctPtr = [&] { return &makeRefA(); }; foo(*fctPtr()); return 0; } 

exit:

 3 3 
+7
c ++ lambda c ++ 11
source share
3 answers

By default, an auto-detected lambda type is a minor version of a type

... the return type is the type of the returned expression (after lvalue-to-rvalue, from array to pointer or implicit conversion of function-to-pointer); (a source)

If you need a return type with a link, you will need to specify it more explicitly. Here are a few options:

 [&]() -> decltype( makeRefA() ) { return makeRefA()); }; 

or just completely explicitly about the return type with ->

 [&]() -> const A& { return makeRefA(); } 

If you are using C ++ 14 just use decltype(auto) ,

 [&]() -> decltype(auto) { return makeRefA(); } 

Rules for decltype can be tricky at times. But the fact that makeRefA() is an expression (as opposed to simply naming a variable) means that the type of the expression ( const A& ) returns decltype( makeRefA() ) correctly.

+7
source share

You can specify the type of return

 #include <functional> #include <iostream> struct A { A(int i) : m(i) { } A(const A&) = delete; int m; }; void foo(const A & a) { std::cout << am <<'\n'; } const A & makeRefA() { static A a(3); return a; } int main() { std::function<const A&()> fctRef = [&]()->const A& // { return std::ref(makeRefA()); }; //compiles ok { return makeRefA(); }; // works foo(fctRef()); std::function<const A*()> fctPtr = [&] { return &makeRefA(); }; foo(*fctPtr()); return 0; } 
+7
source share

According to http://en.cppreference.com/w/cpp/language/lambda , these rules apply to lambdas with no return type:

  • In C ++ 11, lvalue-to-rvalue, array-to-pointer, or function-to-pointer are used for the type of the returned expression. (Here, the lvalue-to-rvalue conversion is what strikes you.)
  • In C ++ 14 and later, the type is inferred as for a function whose type is declared auto ; and this, in turn, is consistent with the rules for subtracting template arguments. Then, since auto does not contain a reference specification, this means that links and cv qualifiers will be ignored.

The effect is probably desirable in most situations: for example, in this lambda expression

 [](const std::vector<int>& v) { return v[0]; } 

you're probably going to return int , although std::vector<int>::operator[] const returns const int& .

As already mentioned, you can override this behavior by specifying an explicit return type.

+2
source share

All Articles