Lambda genérico con función std::no captura variables
Estoy tratando de usar la lambda genérica de C++14, pero tengo un problema con la función std::.
#include <iostream>
#include <functional>
int main()
{
const int a = 2;
std::function<void(int)> f = [&](auto b) { std::cout << a << ", " << b << std::endl; };
f(3);
}
Esto no se compila con un mensaje de error que dice que error: ‘a’ was not declared in this scope
.
Funciona si lo cambio a (int b)
.
¿Es un error? o me estoy perdiendo algo?
La versión de GCC que estoy usando es 4.9.2.
2 answers
Puedo reproducir esto a menos que haga cualquiera de las siguientes cosas:{[14]]}
- eliminar
const
dea
- nombre
a
en la lista de captura - cambiar
std::function<void(int)>
aauto
- haga que la lambda no sea genérica cambiando
auto b
aint b
- use Clang (por ejemplo, v3.5.0)
Creo que este es un error del compilador relacionado con optimizaciones y un fallo al detectar odr-use en una lambda genérica (aunque es interesante que la configuración -O0
tiene sin efecto). Podría estar relacionado con bug 61814 pero no creo que sea bastante lo mismo, por lo tanto:
Lo he planteado como GCC bug 64791.
- (Actualización: este error ha sido marcado como corregido en GCC 5.0.)
Ciertamente no puedo encontrar nada obvio en la redacción de C++14 que debería rechazar su código, aunque hay muy poco "obvio" en general en la nueva redacción de C++14. :(
[C++14: 5.1.2/6]:
[..] Para una lambda genérica sin captura lambda, el tipo de cierre tiene una plantilla de función de conversión const pública no virtual no explícita a puntero a función. La plantilla de función de conversión tiene la misma plantilla inventada template-parameter-list, y el puntero a la función tiene los mismos tipos de parámetros, como la plantilla del operador de llamada a función. [..]
[C++14: 5.1.2/12]:
A lambda-expresión con un asociado capture-default que no captura explícitamente esta o una variable con duración de almacenamiento automático (esto excluye cualquier id-expression que se ha encontrado que se refiere a un init-capture's asociado miembro de datos no estáticos), se dice que captura implícitamente la entidad (es decir,this
o una variable) si la compound-statement :
- odr-utiliza (3.2) la entidad, o
- nombra la entidad en una expresión potencialmente evaluada (3.2) donde la expresión completa que encierra depende de un parámetro lambda genérico declarado dentro del alcance de la expresión lambda .
[ Ejemplo:
void f(int, const int (&)[2] = {}) { } // #1 void f(const int&, const int (&)[1]) { } // #2 void test() { const int x = 17; auto g = [](auto a) { f(x); // OK: calls #1, does not capture x }; auto g2 = [=](auto a) { int selector[sizeof(a) == 1 ? 1 : 2]{}; f(x, selector); // OK: is a dependent expression, so captures x }; }
-end example] Todas estas entidades capturadas implícitamente se declararán dentro del alcance de la expresión lambda. [Nota: La captura implícita de una entidad por una expresión lambda anidada puede causar su captura implícita por la expresión lambda que la contiene (véase más adelante). Implicit odr-los usos de esto pueden resultar en una captura implícita. -nota final ]
[C++14: 5.1.2/13]:
Una entidad es capturada si es capturada explícita o implícitamente. Una entidad capturada por una lambda-expression es odr-used (3.2) en el ámbito que contiene la lambda-expression. [..]
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-03 16:19:02
int main() {
const int a = 2;
auto f = [&](auto b) { std::cout << a << ", " << b << std::endl; };
f(3);
}
No sé si debería funcionar con std::function
pero esto funciona con seguridad.
Investigación adicional:
He creado una clase para imitar lo más cerca posible la lambda:
class Functor {
private:
int const x;
public:
Functor() : x{24} {}
auto operator()(int b) const -> void { cout << x << " " << b << endl; }
};
std::function<auto(int)->void> f2 = Functor{};
f2(3); // <- this works
Esto sugiere que su ejemplo debería haber funcionado. Después de todo, las lambdas tienen el mismo comportamiento con un objeto que tiene los campos operator()
sobrecargados y para las variables capturadas.
Si cambiamos la clase para llegar a la parte auto
:
Esto no funciona:
class Functor {
private:
int const x;
public:
Functor() : x{24} {}
auto operator()(auto b) const -> void { cout << x << " " << b << endl; }
};
std::function<auto(int)->void> f2 = Functor{}; // <-- doesn't work
Sin embargo esto funciona:
class Functor {
private:
int const x;
public:
Functor() : x{24} {}
template <class T>
auto operator()(T b) const -> void { cout << x << " " << b << endl; }
};
std::function<auto(int)->void> f2 = Functor{}; // <-- this works
Así que lo más probable es que esté relacionado con el uso de auto
como parámetro de lambda/functions, una característica nueva en C++14, por lo que lo más probable es que no haya una implementación madura.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-25 21:20:14