Tipo restituito esplicito di Lambda


91

Quando provo a compilare questo codice (VS2010) ricevo il seguente errore: 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;
  });
}

Come ho specificato che lambda ha un tipo di ritorno "void". Inoltre, come faccio a specificare che lambda ha un tipo di ritorno "bool"?

AGGIORNARE

Il seguente compila. Qualcuno può dirmi perché si compila e l'altro no?

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); }));
}

6
Puoi specificarlo esplicitamente con ->, ad esempio[&](double d) -> double { //...
Flexo

2
Ti consiglio di catturare implicitamente le variabili di cui hai bisogno (solo [&]...), poiché ciò che hai attualmente è inutilmente dettagliato.
Xeo

2
[&expression, &start, &end, &what, &flags]...(tuo) vs [&]...(mio). Ora dimmi chi è più prolisso. ;) [&]dice al lambda di catturare tutto ciò che usi all'interno del corpo lambda, per riferimento. Si chiama "cattura predefinita". L'altro è [=]e catturerà per copia.
Xeo

1
@Xeo, Effective Modern C ++, Item 31, consiglia l'acquisizione esplicita, per evitare riferimenti penzolanti. Sono stato morso da questo un paio di volte me stesso come punizione per essere stato pigro ... ehm, conciso. :-)
Emile Cormier

2
A proposito, i vincoli vengono ridotti sui lambda di tipo restituito dedotti in C ++ 14. I tipi restituiti possono essere dedotti per espressioni lambda con più di un'istruzione nel corpo e, purché l'espressione di ciascuna istruzione return abbia lo stesso tipo, ora è possibile avere un tipo restituito dedotto con più istruzioni return.
Anthony Hall

Risposte:


188

È possibile specificare in modo esplicito il tipo restituito di un lambda utilizzando -> Typedopo l'elenco degli argomenti:

[]() -> Type { }

Tuttavia, se un lambda ha un'istruzione e tale istruzione è un'istruzione return (e restituisce un'espressione), il compilatore può dedurre il tipo restituito dal tipo di quella espressione restituita. Hai più istruzioni nel tuo lambda, quindi non deduce il tipo.


4
il compilatore può farlo, ma lo standard gli vieta di farlo.
Johannes Schaub - litb

9
-1: questo non è un bug del compilatore. Lo standard è molto chiaro su questo punto: la sezione 5.1.2, paragrafo 4 stabilisce come viene effettuata la detrazione e in quali condizioni si trova.
Nicol Bolas

2
Sebbene non sia consentito secondo l'ultima bozza, ho trovato che sembra che sia effettivamente consentito nelle specifiche finali andando dal commento per questa patch gcc.gnu.org/ml/gcc-patches/2011-08/msg01901.html . Qualcuno ha le specifiche finali da verificare?
Eelke

2
Ho utilizzato ampiamente le espressioni lambda e non una volta ho dichiarato esplicitamente il tipo restituito. La detrazione del tipo restituito (almeno sotto VS2012 e VS2013) funziona perfettamente anche se c'è più di un'istruzione return nell'espressione lambda. Ovviamente, le varie istruzioni return devono corrispondere all'interno della stessa espressione lambda. Ad esempio un'istruzione come "auto f = [] (int i) {if (i> 5) return true; return false;};" si compila senza problemi e se chiami "auto b = f (10);" b sarà di tipo bool e ovviamente sarà vero;
sprite

1
return nullptr;può lanciare una chiave nella deduzione del tipo, anche se è valido come qualsiasi tipo di puntatore venga altrimenti restituito.
Grault

16

Il tipo restituito di un lambda (in C ++ 11) può essere dedotto, ma solo quando c'è esattamente un'istruzione e quell'istruzione è returnun'istruzione che restituisce un'espressione (un elenco di inizializzatori non è un'espressione, per esempio). Se si dispone di un'espressione lambda con più istruzioni, si presume che il tipo restituito sia void.

Pertanto, dovresti fare questo:

  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;
  })

Ma in realtà, la tua seconda espressione è molto più leggibile.


Bell'esempio; nitpick: la tua chiamata di funzione manca );alla fine?
kevinarpe

6

Puoi avere più di una dichiarazione quando ancora ritorni:

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

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


4
virgola è un operatore rivoltante. confonde le persone che non sono consapevoli della sua esistenza o del suo livello di precedenza. non c'è mai un uso valido neanche imo. può sempre essere evitato con più funzioni o codice altrimenti meglio organizzato.
jheriko

@jheriko sono d'accordo, l'esistenza della mia risposta è solo per chi vuole davvero una soluzione one-liner indipendente XD (è ancora una riga, giusto?). La virgola non è davvero evidente e nessuno metterebbe mai l'intero metodo principale in questa forma.
Valen

1
certo, stai sicuramente dando una risposta valida, semplicemente non sono un fan di aver mai fatto qualcosa per incoraggiare o addirittura dimostrare una cattiva pratica. una volta che le persone imparano che la virgola è un operatore, è un conto alla rovescia finché non iniziano ad abusarne e uno più lungo finché non imparano meglio. :)
jheriko

@jheriko L'ho visto utilizzare in modo interessante in un elenco di inizializzazione dei membri una volta, ma era solo per scherzare, se ricordo bene.
Justin Time - Ripristina Monica il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.