Pregunta

¿Es posible la captura por referencia constante en una expresión lambda?

Quiero la asignación marcado abajo a fallar, 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: Como se trata de una cuestión de edad, podría ser bueno para actualizarlo si hay instalaciones en C ++ 14 para ayudar con esto. Hacer las extensiones en C ++ 14 nos permiten capturar un objeto no constante por referencia constante? ( Agosto el año 2015 )

¿Fue útil?

Solución

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

capture:
  identifier
  & identifier
  this

El texto sólo se menciona la captura-por-copia y captura por referencia y no menciona ningún tipo de const-dad.

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

Otros consejos

C ++ 14:

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

DEMO


C ++ 17:

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

DEMO 2

Creo que la parte de captura no debe especificar const, como el medio de captura, sólo se necesita una manera de acceder a la variable ámbito exterior.

El especificador es mejor se especifica en el alcance exterior.

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

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

supongo que si usted no está utilizando la variable como un parámetro del funtor, entonces debe usar el nivel de acceso de la función actual. Si usted cree que no debe, a continuación, separar su lambda de esta función, que no es parte de ella.

De todos modos, se puede lograr fácilmente lo mismo que desea mediante el uso de otra referencia const en 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 asumir que su lambda tienes que estar aislado de la función actual, por lo que es un no-lambda.

Yo creo que hay tres opciones diferentes:

  • No utilice referencia constante, pero el uso de una captura de copia
  • ignorar el hecho de que es modificable
  • uso std :: unen a bind un argumento de una función binaria que tiene una referencia const.

utilizando una copia

La parte interesante de lambdas con capturas de copia es que aquellos son en realidad sólo lectura y por lo tanto hacer exactamente lo que ellos quieren.

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

using std :: bind

std::bind reduce la aridad de una función. Nota sin embargo que esta fuerza / conducirá 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 un camino más corto.

Tenga en cuenta que no hay ningún signo antes "best_string".

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

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

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

Usar sonido metálico o esperar hasta que este error se fija gcc: error 70385: Lambda captura por referencia de referencia constante falla [ https: // gcc. gnu.org/bugzilla/show_bug.cgi?id=70385 ]

El uso de un const simplemente tener el algoritmo de signo establecer la cadena a su valor original, En otras palabras, el lambda no será realmente definirse como parámetro de la función, aunque el alcance que rodea tendrá una variable adicional ... Sin definirlo sin embargo, no sería definir la cadena como el típico [Y, y best_string] (const string s) Por lo tanto , su más probable mejor si nos dejamos así, tratar de captar la referencia.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top