Explizite Rückgabe Typ von Lambda

91

Wenn ich versuche, diesen Code (VS2010) zu kompilieren, wird folgende Fehlermeldung angezeigt: error C3499: a lambda that has been specified to have a void return type cannot return a value

void DataFile::removeComments()
{
  string::const_iterator start, end;
  boost::regex expression("^\\s?#");
  boost::match_results<std::string::const_iterator> what;
  boost::match_flag_type flags = boost::match_default;
  // Look for lines that either start with a hash (#)
  // or have nothing but white-space preceeding the hash symbol
  remove_if(rawLines.begin(), rawLines.end(), [&expression, &start, &end, &what, &flags](const string& line)
  {
    start = line.begin();
    end = line.end();
    bool temp = boost::regex_search(start, end, what, expression, flags);
    return temp;
  });
}

Wie habe ich angegeben, dass das Lambda einen Rückgabetyp "void" hat? Wie kann ich außerdem angeben, dass das Lambda den Rückgabetyp 'bool' hat?

AKTUALISIEREN

Das Folgende wird kompiliert. Kann mir bitte jemand sagen, warum das kompiliert und der andere nicht?

void DataFile::removeComments()
{
  boost::regex expression("^(\\s+)?#");
  boost::match_results<std::string::const_iterator> what;
  boost::match_flag_type flags = boost::match_default;
  // Look for lines that either start with a hash (#)
  // or have nothing but white-space preceeding the hash symbol
  rawLines.erase(remove_if(rawLines.begin(), rawLines.end(), [&expression, &what, &flags](const string& line)
  { return boost::regex_search(line.begin(), line.end(), what, expression, flags); }));
}
Ryan
quelle
5
Sie können es explizit angeben mit ->zB[&](double d) -> double { //...
Flexo
2
Ich würde Ihnen raten, nur implizit die Variablen zu erfassen, die Sie (nur [&]...) benötigen , da das, was Sie derzeit haben, unnötig ausführlich ist.
Xeo
2
[&expression, &start, &end, &what, &flags]...(deine) gegen [&]...(meine). Jetzt sag mir, wessen ausführlicher ist. ;) [&]weist das Lambda an, alles, was Sie im Lambda-Körper verwenden, als Referenz zu erfassen. Es wird als "Capture-Standard" bezeichnet. Der andere ist [=]und wird per Kopie erfasst.
Xeo
1
@Xeo, Effective Modern C ++, Punkt 31, empfiehlt die explizite Erfassung, um baumelnde Referenzen zu vermeiden. Ich bin selbst ein paar Mal davon gebissen worden, als Strafe dafür, dass ich fauler und prägnanter war. :-)
Emile Cormier
2
Übrigens werden die Einschränkungen für abgeleitete Lambdas vom Rückgabetyp in C ++ 14 reduziert. Rückgabetypen können für Lambdas mit mehr als einer Anweisung im Hauptteil abgeleitet werden. Solange der Ausdruck jeder Rückgabeanweisung denselben Typ hat, können Sie jetzt einen abgeleiteten Rückgabetyp mit mehreren Rückgabeanweisungen haben.
Anthony Hall

Antworten:

188

Sie können den Rückgabetyp eines Lambda explizit angeben, indem Sie -> Typenach der Argumentliste Folgendes verwenden:

[]() -> Type { }

Wenn ein Lambda jedoch eine Anweisung hat und diese Anweisung eine return-Anweisung ist (und einen Ausdruck zurückgibt), kann der Compiler den Rückgabetyp aus dem Typ dieses einen zurückgegebenen Ausdrucks ableiten. Sie haben mehrere Anweisungen in Ihrem Lambda, daher wird der Typ nicht abgeleitet.

Seth Carnegie
quelle
4
Der Compiler kann das, aber der Standard verbietet es, das zu tun.
Johannes Schaub - litb
9
-1: Dies ist kein Compiler-Fehler. Der Standard ist diesbezüglich sehr klar: In Abschnitt 5.1.2, Absatz 4 wird dargelegt, wie und unter welchen Bedingungen der Abzug erfolgt.
Nicol Bolas
2
Obwohl es nach dem neuesten Entwurf nicht erlaubt ist, könnte ich feststellen, dass es tatsächlich in den endgültigen Spezifikationen erlaubt ist, die sich aus dem Kommentar zu diesem Patch ergeben. Gcc.gnu.org/ml/gcc-patches/2011-08/msg01901.html . Hat jemand die endgültige Spezifikation zu überprüfen?
Eelke
2
Ich habe Lambda-Ausdrücke ausgiebig verwendet und den Rückgabetyp nicht ein einziges Mal explizit angegeben. Der Abzug des Rückgabetyps (zumindest unter VS2012 und VS2013) funktioniert einwandfrei, selbst wenn der Lambda-Ausdruck mehr als eine Rückgabeanweisung enthält. Natürlich müssen die verschiedenen return-Anweisungen innerhalb desselben Lambda-Ausdrucks übereinstimmen. ZB eine Anweisung wie "auto f = [] (int i) {if (i> 5) return true; return false;};" Kompiliert ohne Probleme und wenn Sie "auto b = f (10);" b wird vom Typ bool sein und natürlich wahr sein;
Sprite
1
return nullptr;kann einen Schraubenschlüssel in den Typabzug werfen, obwohl er gültig ist, unabhängig davon, welcher Zeigertyp ansonsten zurückgegeben wird.
Grault
16

Der Rückgabetyp eines Lambda (in C ++ 11) kann abgeleitet werden, jedoch nur, wenn genau eine Anweisung vorhanden ist und diese Anweisung eine returnAnweisung ist, die einen Ausdruck zurückgibt (eine Initialisierungsliste ist beispielsweise kein Ausdruck). Wenn Sie ein Lambda mit mehreren Anweisungen haben, wird angenommen, dass der Rückgabetyp ungültig ist.

Deshalb sollten Sie Folgendes tun:

  remove_if(rawLines.begin(), rawLines.end(), [&expression, &start, &end, &what, &flags](const string& line) -> bool
  {
    start = line.begin();
    end = line.end();
    bool temp = boost::regex_search(start, end, what, expression, flags);
    return temp;
  })

Aber wirklich, Ihr zweiter Ausdruck ist viel besser lesbar.

Nicol Bolas
quelle
Schönes Beispiel; nitpick: Fehlt Ihr Funktionsaufruf );am Ende?
Kevinarpe
6

Sie können mehr als eine Anweisung haben, wenn Sie noch zurückkehren:

[]() -> your_type {return (
        your_statement,
        even_more_statement = just_add_comma,
        return_value);}

http://www.cplusplus.com/doc/tutorial/operators/#comma

Valen
quelle
4
Komma ist ein abstoßender Operator. Es verwirrt Menschen, die sich seiner Existenz oder seines Vorrangniveaus nicht bewusst sind. es gibt auch keine gültige verwendung imo. Es kann immer mit mehr Funktionen oder auf andere Weise besser organisiertem Code vermieden werden.
Jheriko
@jheriko stimme zu, die Existenz meiner Antwort ist nur für diejenigen, die wirklich eine unabhängige Einzeiler-Lösung XD wollen (es ist immer noch eine Zeile, oder?). Das Komma fällt wirklich nicht auf, und niemand würde jemals die gesamte Hauptmethode in diese Form bringen.
Valen
1
Sicher, Sie geben mit Sicherheit eine gültige Antwort. Ich bin einfach kein Fan davon, jemals etwas zu tun, um schlechte Praktiken zu fördern oder sogar zu demonstrieren. Sobald die Leute erfahren, dass Komma ein Operator ist, ist es ein Countdown, bis sie anfangen, es zu missbrauchen, und ein längerer, bis sie besser lernen. :)
Jheriko
@jheriko Ich habe gesehen, dass es einmal in einer Mitgliederinitialisierungsliste interessant verwendet wurde, aber das war nur zum Herumspielen, wenn ich mich richtig erinnere.
Justin Time - Stellen Sie Monica