2011-10-25 12 views
16

Chcę znaleźć punkt, który ma mniejszą współrzędną Y (jeśli więcej takich punktów, znajdź ten z najmniejszym X). Pisząc ją lambda:Zwroty 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(); 
    } 

Dostaję:

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

jaka jest różnica pomiędzy:

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

i

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

Konstrukt 'if (wyrażenie) zwraca wartość true; else return false; 'jest zasadniczo brzydki. Dwa razy brzydko, jeśli wyrażenie jest naprawdę boolean. –

+3

@ MichaelKrelin-hacker: To prawda, ale to _nie_, dlaczego kompilator odrzuca ostatni przykład. – MSalters

+1

MSalters, na pewno, dlatego komentuję i nie odpowiadam. To jest odpowiedź na pytanie "jaka jest różnica". I to jest główna różnica;) –

Odpowiedz

13

Typ powrotu lambdas można domyślnie wywnioskować, ale aby to osiągnąć, musisz mieć jedno oświadczenie return; dlatego twoja "działająca" lambda działa (typem powrotnym jest bool).

Rozwiązanie Sehe jawnie deklaruje typ zwrotu, więc działa również dobrze.

Update:

Standard C++ 11 §5.1.2/4 stanowi:

Jeżeli lambda ekspresji nie zawiera zwrotny typu wleczonego , jest jakby zwrotny typu wleczonego oznacza typu:

  • Jeśli związek instrukcja_select jest f orm { return expression ; } typ zwracanego wyrażenia po konwersji l-wartość-r-wartość (4.1), konwersja tablicy-do-wskaźnika (4.2) oraz konwersję funkcji do wskaźnika (4.3);

  • inaczej, void.

Twój lambda nie pracujących spadnie do drugiej kategorii.

+0

Co ciekawe, wikipedia zawiera także * jeśli wszystkie lokalizacje zwracające wartość zwracają ten sam typ, gdy wyrażenie zwrotne jest przekazywane przez 'decltype'. * W zbiorze lambdas, który może pominąć typ zwracany . Wygląda jednak na to, że zgodnie z normą tak nie jest. – mackenir

+0

@Mackenir: Właściwie przed zagłębieniem się w standard myślałem, że może to być również ograniczenie kompilatora (oryginalna odpowiedź jest sformułowana w ten sposób, ale zmiany zostały wprowadzone wkrótce po wysłaniu, więc nie zostały zalogowane). Wikipedia jest zdecydowanie technicznie niepoprawna. – Jon

+0

BTW kupiłeś kopię standardu C++ 11? Nie mogę go znaleźć do bezpłatnego pobrania. – mackenir

12

Jak zauważył Mike, jeśli treść jednostki lambda jest pojedynczą instrukcją zwrotną, to typ powrotu jest wyprowadzany z tego (patrz 5.1.2/4) (dzięki 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; 
} 

Uwaga -> bool.

+0

I prawdopodobnie również dobrze jest wziąć argumenty przez const-reference, ponieważ algorytm może chcieć ci to dać. –

+0

dziękuję! nie powinno być '-> bool' po after() zamiast []? – relaxxx

+0

Sądzę, że tak jest, ponieważ w prostej formie jednoliniowej cmpiler może łatwo wywnioskować typ zwracania, który może nie być w stanie, gdy wprowadzisz warunkowe. Chociaż masz rację, dobrym pomysłem jest wyraźne wyrażenie typu zwrotu. –