precio pick mercedes interior clase camioneta benz 350d c++ c++11 lambda std-function

c++ - pick - ¿Por qué la asignación a std:: function<X()> no se compila cuando es un miembro de la clase X?



mercedes clase x 350 (2)

El siguiente código no compila:

#include <functional> struct X { std::function<X()> _gen; }; int main() { X x; x._gen = [] { return X(); }; //this line is causing problem! }

No entiendo por qué la asignación a x._gen está causando problemas. Tanto gcc como clang están dando mensajes de error similares. ¿Alguien podría por favor explicarlo?

Mensajes de error del compilador

gcc :

In file included from main.cpp:1:0: /usr/include/c++/4.8/functional: In instantiation of ‘std::function<_Res(_ArgTypes ...)>::_Requires<std::function<_Res(_ArgTypes ...)>::_CheckResult<std::function<_Res(_ArgTypes ...)>::_Invoke<_Functor>, _Res>, std::function<_Res(_ArgTypes ...)>&> std::function<_Res(_ArgTypes ...)>::operator=(_Functor&&) [with _Functor = main()::__lambda0; _Res = X; _ArgTypes = {}; std::function<_Res(_ArgTypes ...)>::_Requires<std::function<_Res(_ArgTypes ...)>::_CheckResult<std::function<_Res(_ArgTypes ...)>::_Invoke<_Functor>, _Res>, std::function<_Res(_ArgTypes ...)>&> = std::function<X()>&]’: main.cpp:11:12: required from here /usr/include/c++/4.8/functional:2333:4: error: no matching function for call to ‘std::function<X()>::function(main()::__lambda0)’ function(std::forward<_Functor>(__f)).swap(*this); ^ /usr/include/c++/4.8/functional:2333:4: note: candidates are: /usr/include/c++/4.8/functional:2255:2: note: template<class _Functor, class> std::function<_Res(_ArgTypes ...)>::function(_Functor) function(_Functor); ^ /usr/include/c++/4.8/functional:2255:2: note: template argument deduction/substitution failed: /usr/include/c++/4.8/functional:2230:7: note: std::function<_Res(_ArgTypes ...)>::function(std::function<_Res(_ArgTypes ...)>&&) [with _Res = X; _ArgTypes = {}] function(function&& __x) : _Function_base() ^ /usr/include/c++/4.8/functional:2230:7: note: no known conversion for argument 1 from ‘main()::__lambda0’ to ‘std::function<X()>&&’ /usr/include/c++/4.8/functional:2433:5: note: std::function<_Res(_ArgTypes ...)>::function(const std::function<_Res(_ArgTypes ...)>&) [with _Res = X; _ArgTypes = {}] function<_Res(_ArgTypes...)>:: ^ /usr/include/c++/4.8/functional:2433:5: note: no known conversion for argument 1 from ‘main()::__lambda0’ to ‘const std::function<X()>&’ /usr/include/c++/4.8/functional:2210:7: note: std::function<_Res(_ArgTypes ...)>::function(std::nullptr_t) [with _Res = X; _ArgTypes = {}; std::nullptr_t = std::nullptr_t] function(nullptr_t) noexcept ^ /usr/include/c++/4.8/functional:2210:7: note: no known conversion for argument 1 from ‘main()::__lambda0’ to ‘std::nullptr_t’ /usr/include/c++/4.8/functional:2203:7: note: std::function<_Res(_ArgTypes ...)>::function() [with _Res = X; _ArgTypes = {}] function() noexcept ^ /usr/include/c++/4.8/functional:2203:7: note: candidate expects 0 arguments, 1 provided

Asimismo, clang esto:

main.cpp:11:12: error: no viable overloaded ''='' x._gen = [] { return X(); }; ~~~~~~ ^ ~~~~~~~~~~~~~~~~~~ /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:2270:7: note: candidate function not viable: no known conversion from ''<lambda at main.cpp:11:14>'' to ''const std::function<X ()>'' for 1st argument operator=(const function& __x) ^ /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:2288:7: note: candidate function not viable: no known conversion from ''<lambda at main.cpp:11:14>'' to ''std::function<X ()>'' for 1st argument operator=(function&& __x) ^ /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:2302:7: note: candidate function not viable: no known conversion from ''<lambda at main.cpp:11:14>'' to ''nullptr_t'' for 1st argument operator=(nullptr_t) ^ /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:2192:39: note: candidate template ignored: disabled by ''enable_if'' [with _Functor = <lambda at main.cpp:11:14>] using _Requires = typename enable_if<_Cond::value, _Tp>::type; ^ /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:2340:2: note: candidate template ignored: could not match ''reference_wrapper<type-parameter-0-0>'' against ''<lambda at main.cpp:11:14>'' operator=(reference_wrapper<_Functor> __f) noexcept ^


Esto fue PR60594 , que se corrigió en GCC 4.8.3. Los comentarios sobre ese error señalan por qué es válido: aunque el estándar requiere argumentos de plantilla para que las plantillas de biblioteca estándar sean un tipo completo (con algunas excepciones), X() es un tipo completo, incluso si X no lo es.

Hay varios miembros de std::function<X()> que requieren implícitamente que X sea ​​un tipo completo. El constructor de plantillas que está usando es uno de ellos: requiere que el tipo de retorno de su lambda sea convertible implícitamente a X , pero si X es convertible a sí mismo depende de si X es un tipo completo: si está incompleto, el compilador puede No descarte la posibilidad de que sea un tipo inamovible que no se pueda copiar.

Este requisito se deduce de:

20.9.11.2.1 función construir / copiar / destruir [func.wrap.func.con]

8 Observaciones: Estos constructores no participarán en la resolución de sobrecarga a menos que f sea ​​Callable (20.9.11.2) para los tipos de argumento ArgTypes... y devuelva el tipo R

20.9.11.2 Función de plantilla de clase [func.wrap.func]

2 Un objeto llamable f de tipo F es Callable para los tipos de argumento ArgTypes y devuelve el tipo R si la expresión INVOKE (f, declval<ArgTypes>()..., R) , considerada como un operando no evaluado (Cláusula 5), ​​está bien formado (20.9.2).

20.9.2 Requisitos [func.require]

2 Defina INVOKE (f, t1, t2, ..., tN, R) como INVOKE (f, t1, t2, ..., tN) convertido implícitamente a R

Varios otros miembros de std::function también requieren que X sea ​​un tipo completo.

Sin embargo, solo estás usando ese constructor después de que el tipo X ya se haya completado, así que no hay problema: en ese punto, X puede convertirse implícitamente en X

El problema era que la std::function realizaba verificaciones que dependían de que X fuera un tipo completo, en un contexto en el que el estándar no admite la realización de tales verificaciones, y esto no tenía en cuenta la posibilidad de que X se convirtiera en un tipo completo después de la instanciación de std::function<X()> ya se había completado.


Esto puede ser un error de gcc, pero tal vez no. No está directamente en = sino en el constructor de conversión para std::function (que el operator= invoca).

Aquí hay un ejemplo patológico de lo que está pasando:

#include <iostream> #include <functional> struct X { std::function<X()> _gen; }; X func() {return {};}; int main() { std::function<X()> foo1( &func ); // compiles X unused = X{}; // copy ctor invoked std::function<X()> foo2( &func ); // does not compile! }

tenga en cuenta que el primer foo1 funciona bien, no es hasta que hago que algún código invoque el ctor de copia en el que el segundo genera errores. Incluso auto unused =[]{ return X{}; }; auto unused =[]{ return X{}; }; es suficiente. (construcciones de func directas y nunca copias).

Es el uso / "creación" del ctor de copia lo que parece causar el problema.

#include <iostream> #include <functional> struct X { std::function<X()> _gen; X( X const& ) = default; X() = default; }; X func() {return {};}; int main() { std::function<X()> foo1( &func ); // does not compile }

ese constructor de copias termina llamando al ctor de copia de _gen , posiblemente antes de que X sea ​​un tipo completo.

Si demoramos explícitamente la creación de instancias de X::X(X const&) hasta que X sea ​​un tipo completo:

#include <functional> struct X { std::function<X()> _gen; X( X const& ); X() {} }; X::X( X const& o ):_gen(o._gen){} // or =default *here* X func() {return {};}; int main() { std::function<X()> foo1( &func ); // compiles! []{ return X{}; }; // or X unused = X{}; std::function<X()> foo2( &func ); // compiles! }

el problema desaparece

Sospecho que el constructor de copia implícita de X creado en el cuerpo de X cuando X es un tipo incompleto invoca implícitamente el constructor de copia de std::function<X()> , que está en un contexto donde X está incompleto, lo que rompe el Las condiciones previas a la invocación de su constructor de copia (al menos en la práctica sobre cómo se implementó en gcc - por la norma? No estoy seguro).

Al hacer explícitamente una copia fuera de X , evito esto y todo funciona.

Así que para solucionar su problema, declare e implemente X::X(X const&) fuera de X , y el error mágico desaparece.