23

I want to find point, which has the less Y coordinate (if more of such points, find the one with smallest X). When writing it with lambda:

    std::min_element(begin, end, [](PointAndAngle& p1, PointAndAngle& p2) {
        if (p1.first->y() < p2.first->y())
            return true;
        else if (p1.first->y() > p2.first->y())
            return false;
        else 
            return p1.first->x() < p2.first->x();
    }

I am getting:

error C3499: a lambda that has been specified to have a void return type cannot return a value

what is the difference between:

    // works
    std::min_element(begin, end, [](PointAndAngle& p1, PointAndAngle& p2) {
        return p1.first->y() < p2.first->y();
    }

and

    // does not work
    std::min_element(begin, end, [](PointAndAngle& p1, PointAndAngle& p2) {
        if (p1.first->y() < p2.first->y())
            return true;
        else 
            return false;
    }
Inverse
  • 4,408
  • 2
  • 26
  • 35
relaxxx
  • 7,566
  • 8
  • 37
  • 64

2 Answers2

16

As Mike noted, if the lambda's body is a single return statement, then the return type is inferred from that (see 5.1.2/4) (thanks Mike).

std::min_element(begin, end, [] (const PointAndAngle & p1, const PointAndAngle & p2)
  -> bool 
 {
    if (p1.first->y() < p2.first->y())
         return true;
    else 
        return false;
}

Note -> bool.

sehe
  • 374,641
  • 47
  • 450
  • 633
  • 1
    And probably also good to take the arguments by const-reference, as the algorithm may well want to give you that. – Kerrek SB Oct 25 '11 at 12:18
  • thank you! shouldn't the `-> bool` be after () instead of [] ? – relaxxx Oct 25 '11 at 12:21
  • I guess it is because in the simple one-line form the cmpiler can easily deduce the return type, which he may not be able to once you introduce a conditional. Though you're right in that it is always a good idea to be explicit about the return type. – Christian Rau Oct 25 '11 at 12:22
  • Re "I don't know why the other form works": if the lambda's body is a single return statement, then the return type is inferred from that (see C++11 5.1.2/4). – Mike Seymour Oct 25 '11 at 12:23
  • Thanks Mike for shedding light. That strikes one of my pet peeves with lambdas! Now, can we have deduced argument types?... (PS Have done the fixes mentioned by others) – sehe Oct 25 '11 at 12:27
  • 1
    Two mistakes here: `bool` is in the wrong place, as relaxxx said; and the second line has `return` instead of `if`. – TonyK Oct 25 '11 at 12:27
  • 1
    @TonyK: thanks for the hint. I don't now how I copy/hasted that :) – sehe Oct 25 '11 at 12:27
  • @TonyK: I was in the process of finding out precisely what works and what not to share on IdeOne. However, Mike already explained the rule :) – sehe Oct 25 '11 at 12:30
  • @sehe `auto` parameters have since been added with [generic lambdas in C++14](https://stackoverflow.com/q/17233547). – Lukas Apr 20 '20 at 07:48
14

The return type of lambdas can be implicitly inferred, but you need to have a single return statement to achieve this; that's why your "working" lambda works (return type inferred to be bool).

sehe's solution explicitly declares the return type, so it works fine as well.

Update:

The C++11 standard, §5.1.2/4 states:

If a lambda-expression does not include a trailing-return-type, it is as if the trailing-return-type denotes the following type:

  • If the compound-statement is of the form { return expression ; } the type of the returned expression after lvalue-to-rvalue conversion (4.1), array-to-pointer conversion (4.2), and function-to-pointer conversion (4.3);

  • otherwise, void.

Your not-working lambda falls into the second category.

sehe
  • 374,641
  • 47
  • 450
  • 633
Jon
  • 428,835
  • 81
  • 738
  • 806
  • Interestingly, wikipedia also includes *if all locations that return a value return the same type when the return expression is passed through `decltype`.* in the set of lambdas that may omit the return type. But it looks like, according to the standard, this isn't the case. – mackenir Oct 25 '11 at 12:35
  • @mackenir: Actually before digging into the standard I thought that it might be a compiler limitation as well (the original answer is phrased like that, but the edits were very soon after posting so didn't get logged). Wikipedia is definitely technically incorrect there. – Jon Oct 25 '11 at 12:37
  • BTW did you buy a copy of the C++11 standard? I can't find it for free download. – mackenir Oct 25 '11 at 12:38
  • @mackenir: You can download N3242 from [here](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/). It's not the official standard (just a working copy from February) but the differences should be really minor. – Jon Oct 25 '11 at 12:43