¿Es posible capturar por referencia constante 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: como esta es una pregunta antigua, podría ser bueno actualizarla si hay recursos en C ++ 14 para ayudar con esto. ¿Las extensiones en C ++ 14 nos permiten capturar un objeto no constante con referencia constante? ( Agosto 2015 )
[&, &best_string](string const s) { ...}
:?Respuestas:
const
no está en la gramática para capturas a partir de n3092:El texto solo menciona la captura por copia y la captura por referencia y no menciona ningún tipo de constancia.
Me parece un descuido, pero no he seguido el proceso de estandarización muy de cerca.
fuente
const
. O más correctamente, si la variable de captura fueraconst
, el compilador habría aplicado el comportamiento correcto en el programador. Sería bueno si la sintaxis fuera compatible[&mutableVar, const &constVar]
.a
comoconst
, declareconst auto &b = a;
antes de la lambda y captureb
[&foo = this->foo]
en el interior de unaconst
función me da un error que indica que la captura en sí descarta calificadores. Sin embargo, esto podría ser un error en GCC 5.1, supongo.En c ++ 14usando
static_cast
/const_cast
:MANIFESTACIÓN
En c ++ 17utilizando
std::as_const
:DEMO 2
fuente
const_cast
puede cambiar incondicionalmente un objeto volátil a un objeto constante (cuando se le pide que loconst
static_cast
static_cast
const referencia puede crear silenciosamente un temporal si no obtuvo el tipo exactamente correcto&basic_string = std::as_const(best_string)
debería resolver todos los problemasconst& best_string
.Creo que la parte de captura no debería especificar
const
, ya que la captura significa, solo necesita una forma de acceder a la variable de alcance externo.El especificador se especifica mejor en el alcance externo.
La función lambda es constante (no puede cambiar el valor en su alcance), por lo que cuando captura una variable por valor, la variable no se puede cambiar, pero la referencia no está en el alcance lambda.
fuente
better_string
dentro del alcance que contiene, entonces esta solución no funcionará. El caso de uso para capturar como const-ref es cuando la variable debe ser mutable en el ámbito de contención pero no dentro del lambda.const string &c_better_string = better_string;
y pasarla felizmente a la lambda:[&c_better_string]
Supongo que si no estás usando la variable como parámetro del functor, entonces deberías usar el nivel de acceso de la función actual. Si crees que no deberías, 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:
Pero eso es lo mismo que asumir que su lambda tiene que estar aislada de la función actual, convirtiéndola en no lambda.
fuente
best_string
solo. Aparte de eso, GCC 4.5 "rechaza con éxito" el código como se pretendía.Creo que tienes tres opciones diferentes:
usando una copia
La parte interesante de las lambdas con capturas de copia es que en realidad son de solo lectura y, por lo tanto, hacen exactamente lo que usted desea.
usando std :: bind
std::bind
Reduce la aridad de una función. Sin embargo, tenga en cuenta que esto podría / conducirá a una llamada de función indirecta mediante un puntero de función.fuente
Hay un camino más corto.
Tenga en cuenta que no hay ampersand antes de "best_string".
Será del tipo "const std :: reference_wrapper << T >>".
http://coliru.stacked-crooked.com/a/0e54d6f9441e6867
fuente
Utilice clang o espere hasta que se solucione este error de gcc: error 70385: falla la captura de Lambda por referencia de referencia constante [ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70385 ]
fuente
El uso de una constante simplemente tendrá el algoritmo ampers y establecerá la cadena en su valor original. En otras palabras, el lambda realmente no se definirá como parámetro de la función, aunque el alcance circundante tendrá una variable adicional ... Sin definirlo sin embargo, no definiría la cadena como la típica [&, & best_string] (cadena const s) Por lo tanto , lo más probable es que sea mejor si la dejamos así, tratando de capturar la referencia.
fuente