Tipo de retorno explícito de Lambda

94

Cuando intento compilar este código (VS2010), aparece el siguiente error: 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;
  });
}

¿Cómo especifiqué que el lambda tiene un tipo de retorno 'vacío'? Además, ¿cómo especifico que la lambda tiene el tipo de retorno 'bool'?

ACTUALIZAR

Lo siguiente compila. ¿Alguien puede decirme por qué se compila y el otro 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); }));
}
Ryan
fuente
6
Puede especificarlo explícitamente con ->, por ejemplo,[&](double d) -> double { //...
Flexo
2
Te aconsejo que captures implícitamente las variables que necesitas (solo [&]...), ya que lo que tienes actualmente es innecesariamente detallado.
Xeo
2
[&expression, &start, &end, &what, &flags]...(el tuyo) vs [&]...(el mío). Ahora dime de quién es más detallado. ;) [&]le dice a la lambda que capture todo lo que usa dentro del cuerpo lambda, por referencia. Se llama "captura predeterminada". El otro es [=]y capturará por copia.
Xeo
1
@Xeo, Effective Modern C ++, Item 31, recomienda capturar explícitamente, para evitar referencias colgantes. Me ha mordido eso un par de veces como castigo por ser vago ... er, conciso. :-)
Emile Cormier
2
Por cierto, las restricciones se reducen en lambdas de tipo de retorno deducidas en C ++ 14. Los tipos de devolución se pueden deducir para lambdas con más de una declaración en el cuerpo, y siempre que la expresión de cada declaración de devolución tenga el mismo tipo, ahora puede tener un tipo de devolución deducido con varias declaraciones de devolución.
Anthony Hall

Respuestas:

195

Puede especificar explícitamente el tipo de retorno de una lambda utilizando -> Type después de la lista de argumentos:

[]() -> Type { }

Sin embargo, si una lambda tiene una declaración y esa declaración es una declaración de retorno (y devuelve una expresión), el compilador puede deducir el tipo de retorno del tipo de esa expresión devuelta. Tiene varias declaraciones en su lambda, por lo que no deduce el tipo.

Seth Carnegie
fuente
4
el compilador puede hacer eso, pero el estándar lo prohíbe.
Johannes Schaub - litb
10
-1: Esto no es un error del compilador. La norma es muy clara al respecto: la sección 5.1.2, párrafo 4, establece cómo se realiza la deducción y en qué condiciones.
Nicol Bolas
2
Si bien no está permitido según el último borrador, pude encontrar que parece que en realidad está permitido en las especificaciones finales según el comentario de este parche gcc.gnu.org/ml/gcc-patches/2011-08/msg01901.html . ¿Alguien tiene la especificación final para verificar?
Eelke
2
He usado expresiones lambda ampliamente y ni una sola vez indiqué explícitamente el tipo de retorno. La deducción del tipo de devolución (al menos en VS2012 y VS2013) funciona perfectamente incluso si hay más de una declaración de devolución en la expresión lambda. Por supuesto, las diversas declaraciones de retorno deben coincidir dentro de la misma expresión lambda. Por ejemplo, una declaración como "auto f = [] (int i) {if (i> 5) return true; return false;};" se compila sin problemas y si llama "auto b = f (10);" b será de tipo bool y, por supuesto, verdadero;
sprite
1
return nullptr;puede lanzar una llave inglesa en la deducción de tipo, aunque es válido ya que cualquier tipo de puntero se devuelve.
Grault
16

El tipo de retorno de una lambda (en C ++ 11) se puede deducir, pero solo cuando hay exactamente una declaración, y esa declaración es una returndeclaración que devuelve una expresión (una lista de inicializadores no es una expresión, por ejemplo). Si tiene una lambda de declaración múltiple, se supone que el tipo de retorno es nulo.

Por lo tanto, debes hacer esto:

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

Pero en realidad, tu segunda expresión es mucho más legible.

Nicol Bolas
fuente
Buen ejemplo; nitpick: ¿Falta la llamada de función );al final?
kevinarpe
6

Puede tener más de una declaración cuando aún regrese:

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

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

Valen
fuente
4
coma es un operador repugnante. confunde a las personas que no son conscientes de su existencia o nivel de precedencia. Tampoco hay un uso válido en mi opinión. siempre se puede evitar con más funciones o con un código mejor organizado.
jheriko
@jheriko está de acuerdo, la existencia de mi respuesta es solo para aquellos que realmente quieren una solución independiente de una sola línea XD (sigue siendo una línea, ¿verdad?). La coma realmente no se nota, y nadie pondría el método principal completo en esta forma.
Valen
1
Claro, ciertamente estás dando una respuesta válida, simplemente no soy un fanático de hacer algo para alentar o incluso demostrar una mala práctica. una vez que las personas aprenden que la coma es un operador, es una cuenta regresiva hasta que comienzan a abusar de ella y una más larga hasta que aprenden mejor. :)
jheriko
@jheriko He visto que se le ha dado un uso interesante en una lista de inicialización de miembros una vez, pero eso fue solo para jugar, si no recuerdo mal.
Justin Time - Reincorpora a Monica