studio programacion para móviles libros libro edición desarrollo curso aplicaciones c++ templates stl c++11 custom-errors

c++ - programacion - ¿Herramientas para generar mensajes de error de mayor calidad para el código basado en plantillas?



manual de programacion android pdf (3)

Atentos a una respuesta (marqué esta wiki de la comunidad para obtener una buena respuesta juntos) ...

Estoy trabajando desde hace mucho tiempo con las plantillas y los mensajes de error han mejorado en general de una manera u otra:

  • Escribir una pila de errores crea mucho más texto, pero generalmente también incluye el nivel que el usuario está mirando y esto generalmente incluye una pista sobre cuál es el problema real. Dado que el compilador solo ve una unidad de traducción lanzada, no hay mucho que pueda hacerse para determinar qué error en la pila es el más adecuado para el usuario.
  • El uso de verificadores conceptuales, es decir, clases o funciones que ejercitan todos los miembros requeridos de los argumentos de la plantilla y posiblemente generando mensajes de error utilizando static_assert() da al autor de la plantilla una forma de informar a los usuarios sobre supuestos que aparentemente no se cumplen.
  • También ayuda el hecho de decirle al usuario sobre los tipos que escribe en lugar de expandir todos los typedefs, como le gusta ver al compilador en el nivel más bajo. clang es bastante bueno en esto y realmente te da mensajes de error, por ejemplo, hablando de std::string lugar de expandir el tipo de cosas a lo que termine siendo.

Una combinación de la técnica hace que, por ejemplo, clang cree un mensaje de error bastante decente (incluso si no implementa C ++ 2011, sin embargo, ningún compilador lo hace y, por lo que puedo decir, gcc y clang lideran el paquete) . Sé que otros desarrolladores de compiladores trabajan activamente para mejorar los mensajes de error de la plantilla, ya que muchos programadores han descubierto que las plantillas en realidad representan un gran avance, aunque los mensajes de error son algo que nos lleva un poco de tiempo acostumbrarnos.

Un problema con las herramientas como stlfilt es que los compiladores y las bibliotecas de C ++ están en desarrollo activo. Esto da como resultado mensajes de error que cambian todo el tiempo, haciendo que la herramienta reciba salidas diferentes. Si bien es bueno que los escritores de compiladores trabajen en la mejora de los mensajes de error, ciertamente hace la vida más difícil para las personas que intentan trabajar a partir de los mensajes de error que recibieron. También hay otro lado en esto: una vez que se detecta que un determinado patrón de error es común y se recoge, por ejemplo, mediante stlfilt (bueno, no se mantiene activamente hasta donde yo sé), los escritores de compiladores probablemente estén dispuestos a informar los errores. seguir estos patrones directamente, posiblemente también proporcionando información adicional disponible para el compilador pero no emitida antes. Dicho de otra manera, esperaría que los escritores de compiladores sean bastante receptivos a los informes de los usuarios que describen situaciones de error comunes y cómo se informan mejor. Los escritores del compilador pueden no encontrar los errores porque el código en el que están trabajando es C (por ejemplo, gcc está implementado en C) o porque están acostumbrados a ciertas técnicas de plantilla que evitan ciertos errores (por ejemplo, omisión de typename para tipos dependientes )

Finalmente, para abordar la pregunta sobre las herramientas concretas: la principal "herramienta" que estoy usando cuando me quedo atrapado con un compilador quejándose de la instanciación de una plantilla es usar compiladores diferentes. Aunque no siempre es el caso, a menudo un compilador informa un mensaje de error completamente incomprensible que solo tiene sentido después de ver el informe bastante conciso de otro compilador (en caso de que esté interesado, regularmente uso la versión más reciente de gcc, clang y EDG). para esto). Sin embargo, no estoy al tanto de un paquete fácil como stlfilt.

Concepts que harían innecesarias estas herramientas no son parte de C ++ 11 .

  • STLFilt hubiera sido una opción pero ya no se mantiene.

  • Clang afirma brindar diagnósticos expresivos, aunque las características importantes de C ++ 11 aún no están disponibles.

  • colorgcc parece estar abandonado desde 1999.

¿Qué herramientas de calidad de producción están disponibles para descifrar los mensajes de error derivados del código basado en plantilla? El soporte de Eclipse-CDT sería bueno también. :)

Si renuncio a C ++ 11, ¿qué opciones tengo para C ++ 98?

Preguntas relacionadas:

  • Descifrar los mensajes de error de la plantilla de C ++
  • Mejorando la salida de g ++

Encontré Clang para generar los mejores mensajes de error para el código con muchas plantillas. Por supuesto, la verbosidad es inevitable en la mayoría de los casos, pero sigue siendo mejor que GCC o MSVC la mayor parte del tiempo. Aquí está el mensaje de error de Clang para el código de ejemplo publicado por AshleysBrain:

$ clang++ -std=c++11 -stdlib=libc++ -o dummy dummy.cpp In file included from dummy.cpp:1: In file included from /usr/include/c++/v1/vector:243: In file included from /usr/include/c++/v1/__bit_reference:15: In file included from /usr/include/c++/v1/algorithm:594: /usr/include/c++/v1/memory:1425:36: error: calling a private constructor of class ''std::__1::unique_ptr<int, std::__1::default_delete<int> >'' ::new ((void*)__p) _Tp(_STD::forward<_Args>(__args)...); ^ /usr/include/c++/v1/memory:1358:14: note: in instantiation of function template specialization ''std::__1::allocator_traits<std::__1::allocator<std::__1::unique_ptr<int, std::__1::default_delete<int> > > >::__construct<std::__1::unique_ptr<int, std::__1::default_delete<int> >, std::__1::unique_ptr<int, std::__1::default_delete<int> > &>'' requested here {__construct(__has_construct<allocator_type, pointer, _Args...>(), ^ /usr/include/c++/v1/vector:781:25: note: in instantiation of function template specialization ''std::__1::allocator_traits<std::__1::allocator<std::__1::unique_ptr<int, std::__1::default_delete<int> > > >::construct<std::__1::unique_ptr<int, std::__1::default_delete<int> >, std::__1::unique_ptr<int, std::__1::default_delete<int> > &>'' requested here __alloc_traits::construct(__a, _STD::__to_raw_pointer(this->__end_), *__first); ^ /usr/include/c++/v1/vector:924:9: note: in instantiation of function template specialization ''std::__1::vector<std::__1::unique_ptr<int, std::__1::default_delete<int> >, std::__1::allocator<std::__1::unique_ptr<int, std::__1::default_delete<int> > > >::__construct_at_end<std::__1::unique_ptr<int, std::__1::default_delete<int> > *>'' requested here __construct_at_end(__x.__begin_, __x.__end_); ^ dummy.cpp:7:37: note: in instantiation of member function ''std::__1::vector<std::__1::unique_ptr<int, std::__1::default_delete<int> >, std::__1::allocator<std::__1::unique_ptr<int, std::__1::default_delete<int> > > >::vector'' requested here std::vector<unique_ptr<int>> bar = foo; ^ /usr/include/c++/v1/memory:1997:5: note: declared private here unique_ptr(const unique_ptr&); ^ 1 error generated.

Todavía es largo y feo, pero en mi opinión está mucho más claro sobre qué / dónde está el problema.


Sé que puede que esto no sea tan útil como quisiste, pero he encontrado que la mejor herramienta contra los mensajes de error de la plantilla es el conocimiento .

Una buena comprensión del STL y cómo usarlo lo ayudará a evitar muchos errores en primer lugar. En segundo lugar, a menudo los mensajes de error se refieren a las funciones en la fuente STL: si tiene una idea aproximada de cómo se implementa el STL, esto puede ser extremadamente útil para descifrar de qué se trata el mensaje de error. Finalmente, los fabricantes de compiladores son conscientes de este problema y están mejorando gradualmente la salida de mensajes de error, por lo que haría bien en apegarse a la última versión de su compilador.

Aquí hay un buen ejemplo de un error de plantilla oscuro:

std::vector<std::unique_ptr<int>> foo; std::vector<std::unique_ptr<int>> bar = foo;

unique_ptr no se puede copiar, solo se puede mover. Así que tratar de asignar un vector de unique_ptr a otro vector significará que en algún lugar del vector el código fuente intentará copiar un puntero único. Por lo tanto, el error se originará en un código que no es suyo y arrojará un mensaje de error bastante opaco como resultado. El mensaje de error ideal sería

main.cpp (20): no se puede construir ''bar'' desde ''foo'': el tipo de plantilla de foo no se puede copiar

En cambio, VS2010 produce el siguiente error:

1>C:/Program Files (x86)/Microsoft Visual Studio 10.0/VC/include/xmemory(48): error C2248: ''std::unique_ptr<_Ty>::unique_ptr'' : cannot access private member declared in class ''std::unique_ptr<_Ty>'' 1> with 1> [ 1> _Ty=int 1> ] 1> C:/Program Files (x86)/Microsoft Visual Studio 10.0/VC/include/memory(2347) : see declaration of ''std::unique_ptr<_Ty>::unique_ptr'' 1> with 1> [ 1> _Ty=int 1> ] 1> C:/Program Files (x86)/Microsoft Visual Studio 10.0/VC/include/xmemory(197) : see reference to function template instantiation ''void std::_Construct<std::unique_ptr<_Ty>,const std::unique_ptr<_Ty>&>(_Ty1 *,_Ty2)'' being compiled 1> with 1> [ 1> _Ty=int, 1> _Ty1=std::unique_ptr<int>, 1> _Ty2=const std::unique_ptr<int> & 1> ] 1> C:/Program Files (x86)/Microsoft Visual Studio 10.0/VC/include/xmemory(196) : while compiling class template member function ''void std::allocator<_Ty>::construct(std::unique_ptr<int> *,const _Ty &)'' 1> with 1> [ 1> _Ty=std::unique_ptr<int> 1> ] 1> C:/Program Files (x86)/Microsoft Visual Studio 10.0/VC/include/vector(421) : see reference to class template instantiation ''std::allocator<_Ty>'' being compiled 1> with 1> [ 1> _Ty=std::unique_ptr<int> 1> ] 1> C:/Program Files (x86)/Microsoft Visual Studio 10.0/VC/include/vector(481) : see reference to class template instantiation ''std::_Vector_val<_Ty,_Alloc>'' being compiled 1> with 1> [ 1> _Ty=std::unique_ptr<int>, 1> _Alloc=std::allocator<std::unique_ptr<int>> 1> ] 1> main.cpp(19) : see reference to class template instantiation ''std::vector<_Ty>'' being compiled 1> with 1> [ 1> _Ty=std::unique_ptr<int> 1> ]

Examinando esto hay pistas. La primera sección hace referencia a un acceso de miembro privado de std::unique_ptr<int> . La segunda sección, si hace clic en la línea de origen, apunta al constructor de copia de unique_ptr , que se declara debajo de un private: especificador. Entonces ahora sabemos que intentamos copiar un unique_ptr que no está permitido. Las secciones 3, 4 y 5 solo apuntan al código repetitivo, es solo ruido. La Sección 6 dice "ver compilación de la instanciación de la plantilla de clase ''std :: _ Vector_val <_Ty, _Alloc>''. En otras palabras, este error ocurrió en el código de la plantilla del vector. La última sección es muy interesante: apunta directamente a la línea que declara foo en tu propio código fuente: ¡se descifró en qué parte de tu código fuente se originó el error!

Así que sumando las pistas:

  • Se origina en foo,
  • Se origina en el código vectorial,
  • Intenta copiar un unique_ptr que no está permitido.
  • Conclusión: el vector intentó copiar uno de sus elementos, lo cual no está permitido. Revisa el código de foo y busca cualquier cosa que cause una copia.

Dado que el compilador solo apuntó a la declaración de foo, si la asignación está muy alejada en el código fuente, habrá algo de caza involucrado. Obviamente, esto no es ideal, pero creo que este enfoque finalmente te brinda más posibilidades de corregir errores en general. Comenzarás a reconocer que ese tipo de volcado de error significa "has copiado un unique_ptr". De nuevo, no estoy defendiéndolo, definitivamente necesita mejorar, pero creo que en estos días solo hay suficiente información en la salida que, combinada con un buen conocimiento de la STL, le permite solucionar el problema.