compiler compilador c++ gcc c++14

c++ - compilador - El lambda genérico con std:: función no captura variables



gcc c++ (2)

Puedo reproducir esto a menos que haga cualquiera de los siguientes:

  • eliminar const de a
  • nombre a en la lista de captura
  • cambie std::function<void(int)> a auto
  • hacer que la lambda no sea genérica cambiando auto b a int b
  • use Clang (por ej. v3.5.0)

Creo que esto es un error del compilador relacionado con las optimizaciones y una falla al detectar odr-use en un lambda genérico (aunque es interesante que la configuración -O0 no tenga ningún efecto). Podría estar relacionado con el error 61814 pero no creo que sea lo mismo, por lo tanto:

Lo he planteado como error GCC 64791 .

  • (Actualización: este error se marcó como corregido en GCC 5.0).

Ciertamente no puedo encontrar nada obvio en la redacción de C ++ 14 que debería denegar 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 un lambda genérico sin captura lambda, el tipo de cierre tiene una plantilla de función pública de conversión no virtual no virtual para señalar a la función. La plantilla de función de conversión tiene la misma plantilla-lista-lista inventada, y el puntero a función tiene los mismos tipos de parámetros, que la plantilla de operador de llamada a función. [..]

[C++14: 5.1.2/12]: una expresión lambda con un valor predeterminado de captura asociado que no captura explícitamente esta o una variable con duración de almacenamiento automático (esto excluye cualquier expresión de id que se haya encontrado que haga referencia a un miembro de datos no estático asociado a la captura de inicio ), se dice que captura implícitamente la entidad (es decir, this o una variable) si el enunciado compuesto :

  • odr-usa (3.2) la entidad, o
  • nombra la entidad en una expresión potencialmente evaluada (3.2) donde la expresión completa envolvente depende de un parámetro lambda genérico declarado dentro del alcance de 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 }; }

-ejemplo] Todas esas entidades capturadas implícitamente se declararán dentro del alcance de 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 lo contiene (ver a continuación). Odr-usos implícitos de esto puede resultar en captura implícita. -finalizar nota]

[C++14: 5.1.2/13]: una entidad se captura si se captura explícita o implícitamente. Una entidad capturada por una expresión lambda se usa odr (3.2) en el ámbito que contiene la expresión lambda . [..]

Estoy tratando de usar el lambda genérico de C ++ 14, pero tuve 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 puede compilar con un mensaje de error que dice que el 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.


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 la std::function pero esto funciona con seguridad.

Investigación exahustiva:

Creé una clase para imitar lo más fielmente 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 tu ejemplo debería haber funcionado. Después de todo, las lambdas tienen el mismo comportamiento con un objeto que tiene el operator() sobrecargado y campos para las variables capturadas.

Si cambiamos la clase para llegar a la parte de 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

Por lo tanto, lo más probable es que esté relacionado con el uso de auto como parámetro de lambda / funciones, una característica nueva en C ++ 14, probablemente sin una implementación madura.