funciones examples c++ c++11 lambda c++14

c++ - examples - ¿Captura Lambda como referencia constante?



lambda examples c++ (8)

¿Es posible capturar por referencia de const en una expresión lambda?

Quiero que la tarea marcada a continuación falle, por ejemplo:

#include <cstdlib> #include <vector> #include <string> #include <algorithm> using namespace std; int main() { string strings[] = { "hello", "world" }; static const size_t num_strings = sizeof(strings)/sizeof(strings[0]); string best_string = "foo"; for_each( &strings[0], &strings[num_strings], [&best_string](const string& s) { best_string = s; // this should fail } ); return 0; }

Actualización: ya que esta es una pregunta antigua, podría ser bueno actualizarla si hay instalaciones en C ++ 14 para ayudar con esto. ¿Las extensiones en C ++ 14 nos permiten capturar un objeto no const por referencia constante? ( Agosto de 2015 )


Actualización: ya que esta es una pregunta antigua, podría ser bueno actualizarla si hay instalaciones en C ++ 14 para ayudar con esto. ¿Las extensiones en C ++ 14 nos permiten capturar un objeto no const por referencia constante?

[&best_string = static_cast<const std::string&>(best_string)](const string& s) { best_string = s; // fails };

DEMO


Creo que la parte de captura no debe especificar const , ya que la captura significa que solo necesita una forma de acceder a la variable de ámbito externo.

El especificador se especifica mejor en el ámbito externo.

const string better_string = "XXX"; [&better_string](string s) { better_string = s; // error: read-only area. }

La función lambda es const (no puede cambiar el valor en su alcance), por lo que cuando se captura una variable por valor, la variable no se puede cambiar, pero la referencia no está en el alcance lambda.


Creo que tienes tres opciones diferentes:

  • no use referencia de referencia, pero use una copia de captura
  • ignorar el hecho de que es modificable
  • use std :: bind para enlazar un argumento de una función binaria que tenga una referencia constante.

usando una copia

La parte interesante acerca de lambdas con capturas de copia es que son solo de lectura y por lo tanto hacen exactamente lo que usted quiere.

int main() { int a = 5; [a](){ a = 7; }(); // Compiler error! }

usando std :: bind

std::bind reduce la aridad de una función. Sin embargo, tenga en cuenta que esto podría / dará lugar a una llamada de función indirecta a través de un puntero de función.

int main() { int a = 5; std::function<int ()> f2 = std::bind( [](const int &a){return a;}, a); }


Hay una manera más corta.

Tenga en cuenta que no hay un signo & antes de "best_string".

Será del tipo "const std :: reference_wrapper << T >>".

[best_string = cref(best_string)](const string& s) { best_string = s; // fails };

http://coliru.stacked-crooked.com/a/0e54d6f9441e6867


Supongo que si no está usando la variable como un parámetro del functor, entonces debe usar el nivel de acceso de la función actual. Si crees que no deberías, entonces separa tu lambda de esta función, no es parte de ella.

De todos modos, puede lograr fácilmente lo mismo que desea utilizando otra referencia constante en su lugar:

#include <cstdlib> #include <vector> #include <string> #include <algorithm> using namespace std; int main() { string strings[] = { "hello", "world" }; static const size_t num_strings = sizeof(strings)/sizeof(strings[0]); string best_string = "foo"; const string& string_processed = best_string; for_each( &strings[0], &strings[num_strings], [&string_processed] (const string& s) -> void { string_processed = s; // this should fail } ); return 0; }

Pero eso es lo mismo que suponer que su lambda tiene que estar aislada de la función actual, por lo que es un no lambda.


Usar un const simplemente tendrá el algoritmo y el conjunto de la cadena a su valor original, en otras palabras, la lambda no se definirá realmente como parámetro de la función, aunque el ámbito circundante tendrá una variable adicional ... Sin definirlo sin embargo, no definiría la cadena como la típica [&, & best_string] (const s de cadena) Por lo tanto , es mucho mejor si simplemente lo dejamos así, tratando de capturar la referencia.



const no está en la gramática para capturas a partir de n3092:

capture: identifier & identifier this

El texto solo menciona captura por copia y captura por referencia y no menciona ningún tipo de const-ness.

Se siente como un descuido para mí, pero no he seguido el proceso de estandarización muy de cerca.