Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I return from a function inside a lambda?

Tags:

Consider the following toy code to determine whether a range contains an element:

template<typename Iter, typename T> bool contains1(Iter begin, Iter end, const T& x) {     for (; begin != end; ++begin)     {         if (*begin == x) return true;     }     return false; } 

(Yes I know, there are already perfectly fine algorithms in the standard library, that's not the point.)

How would I write the same thing with for_each and a lambda? The following doesn't work...

template<typename Iter, typename T> bool contains2(Iter begin, Iter end, const T& x) {     std::for_each(begin, end, [&x](const T& y) {         if (x == y) return true;     });     return false; } 

...because that would only return from the lambda, not from the function.

Do I have to throw an exception to get out of the lambda? Again, there are probably a dozen better solutions to this specific problem that do not involve lambdas at all, but that's not what I'm asking for.

like image 283
fredoverflow Avatar asked Sep 03 '11 07:09

fredoverflow


People also ask

Can you return in a lambda expression?

A return statement is not an expression in a lambda expression. We must enclose statements in braces ({}). However, we do not have to enclose a void method invocation in braces. The return type of a method in which lambda expression used in a return statement must be a functional interface.

What is return type in lambda?

The return type for a lambda is specified using a C++ feature named 'trailing return type'. This specification is optional. Without the trailing return type, the return type of the underlying function is effectively 'auto', and it is deduced from the type of the expressions in the body's return statements.

Can a lambda function return two values?

That's not more than one return, it's not even a single return with multiple values. It's one return with one value (which happens to be a tuple).

How do you return a value from a lambda function in C++?

Lambda expression in C++ Generally return-type in lambda expression are evaluated by compiler itself and we don't need to specify that explicitly and -> return-type part can be ignored but in some complex case as in conditional statement, compiler can't make out the return type and we need to specify that.


2 Answers

How would I write the same thing with for_each and a lambda?

You can’t (leaving aside exceptions). Your function isn’t isomorphic to a for-each loop (= kind of a mapping), it’s as simple as that.

Instead, your function is described by a reduction so if you want to use higher-order functions to replace it, use a reduction, not a map.

If C++ had an appropriate, general-purpose reduce then your algorithm would look as follows:

template<typename Iter, typename T> bool contains2(Iter begin, Iter end, const T& x) {     return stdx::reduce(begin, end, [&x](const T& y, bool accumulator) {         return accumulator or x == y;     }); } 

Of course, this only exits early if the reduction is properly specialised for boolean result values, in order to short-circuit.

Alas, C++ doesn’t offer such a functionality as far as I see. There’s accumulate but that won’t short-circuit (it can’t – C++ doesn’t know that the operation inside the lambda is short-circuited, and it isn’t implemented recursively).

like image 171
Konrad Rudolph Avatar answered Oct 16 '22 05:10

Konrad Rudolph


std::for_each is not the algorithm you should use if you want to end the loop early. It seems you want std::find_if or something similar. You should use the algorithm that is most appropriate to your task, not just the one you're familiar with.


If you really, really, really must "return" from an algorithm early, you can-

Warning: what follows is a really, really bad idea and you should virtually never do it. Indeed, looking at the code may melt your face. You have been warned!

Throw an exception:

bool contains2(Iter begin, Iter end, const T& x) {   try {     std::for_each(begin, end, [&x](const T& y) {         if (x == y)           throw std::runtime_error("something");     });   }   catch(std::runtime_error &e) {     return true;   }   return false; } 
like image 44
Nicol Bolas Avatar answered Oct 16 '22 03:10

Nicol Bolas