¿Existe un static_warning?

Soy consciente de esta pregunta que menciona la “ADVERTENCIA ESTÁTICA” de Boost, pero me gustaría preguntar de nuevo, específicamente, cómo podría implementar un static_warning que funciona de manera similar a static_assert pero solo emite una advertencia en tiempo de comstackción en lugar de una comstackción abortiva error.

Me gustaría algo similar a la propuesta de Alexandrescu para una afirmación estática en pre-C ++ 11 días que de alguna manera logró imprimir información contextual útil como parte del error.

Sería aceptable exigir que el usuario habilite ciertas advertencias de comstackdor estándar para que esta construcción funcione (tal vez “conversión de puntero no válido” o “rompe reglas de alias estrictas”) – cualquier advertencia que debe ser parte de una comstackción normal de todos modos puede ser usado.

En resumen, quiero static_warning(false, "Hello world"); para crear una advertencia del comstackdor que de alguna manera debería incluir la cadena “hello world” en el mensaje de advertencia. ¿Es esto posible, digamos en GCC y MSVC, y cómo?

Felizmente daría una pequeña recompensa de recompensa por cualquier solución especialmente inteligente.


Como explicación: obtuve la idea cuando pensé en esta pregunta : una advertencia estática sería una forma útil de rastrear el proceso en tiempo de comstackción de las especializaciones complejas de plantillas, que de otro modo serían bastante difíciles de depurar. Una advertencia estática podría usarse como un simple faro para que el comstackdor emita “Ahora estoy comstackndo esta parte del código”.


Actualizar. Idealmente, la advertencia se activaría en la siguiente configuración:

 template  struct Foo { static_warning(std::is_pointer::value, "Attempting to use pointer type."); // ... }; int main() { Foo a; Foo b; } 

Jugando el comentario de Michael E:

 #if defined(__GNUC__) #define DEPRECATE(foo, msg) foo __attribute__((deprecated(msg))) #elif defined(_MSC_VER) #define DEPRECATE(foo, msg) __declspec(deprecated(msg)) foo #else #error This compiler is not supported #endif #define PP_CAT(x,y) PP_CAT1(x,y) #define PP_CAT1(x,y) x##y namespace detail { struct true_type {}; struct false_type {}; template  struct converter : public true_type {}; template <> struct converter<0> : public false_type {}; } #define STATIC_WARNING(cond, msg) \ struct PP_CAT(static_warning,__LINE__) { \ DEPRECATE(void _(::detail::false_type const& ),msg) {}; \ void _(::detail::true_type const& ) {}; \ PP_CAT(static_warning,__LINE__)() {_(::detail::converter<(cond)>());} \ } // Note: using STATIC_WARNING_TEMPLATE changes the meaning of a program in a small way. // It introduces a member/variable declaration. This means at least one byte of space // in each structure/class instantiation. STATIC_WARNING should be preferred in any // non-template situation. // 'token' must be a program-wide unique identifier. #define STATIC_WARNING_TEMPLATE(token, cond, msg) \ STATIC_WARNING(cond, msg) PP_CAT(PP_CAT(_localvar_, token),__LINE__) 

La macro se puede invocar en el espacio de nombres, la estructura y el scope de la función. Dada la entrada:

 #line 1 STATIC_WARNING(1==2, "Failed with 1 and 2"); STATIC_WARNING(1<2, "Succeeded with 1 and 2"); struct Foo { STATIC_WARNING(2==3, "2 and 3: oops"); STATIC_WARNING(2<3, "2 and 3 worked"); }; void func() { STATIC_WARNING(3==4, "Not so good on 3 and 4"); STATIC_WARNING(3<4, "3 and 4, check"); } template  struct wrap { typedef T type; STATIC_WARNING(4==5, "Bad with 4 and 5"); STATIC_WARNING(4<5, "Good on 4 and 5"); STATIC_WARNING_TEMPLATE(WRAP_WARNING1, 4==5, "A template warning"); }; template struct wrap; 

GCC 4.6 (en el nivel de advertencia predeterminado) produce:

 static_warning.cpp: en el constructor 'static_warning1 :: static_warning1 ()':
 static_warning.cpp: 1: 1: advertencia: 'void static_warning1 :: _ (const detail :: false_type &)' 
     está en desuso (declarado en static_warning.cpp: 1): Falló con 1 y 2 [-Wdeprecated-declarations]
 static_warning.cpp: en el constructor 'Foo :: static_warning6 :: static_warning6 ()':
 static_warning.cpp: 6: 3: warning: 'void Foo :: static_warning6 :: _ (const detail :: false_type &)'
     está en desuso (declarado en static_warning.cpp: 6): 2 y 3: oops [-Wdeprecated-declarations]
 static_warning.cpp: en el constructor 'func () :: static_warning12 :: static_warning12 ()':
 static_warning.cpp: 12: 3: warning: 'void func () :: static_warning12 :: _ (const detail :: false_type &)' 
     está en desuso (declarado en static_warning.cpp: 12): No tan bueno en 3 y 4 [-Wdeprecated-declarations]
 static_warning.cpp: en el constructor 'wrap  :: static_warning19 :: static_warning19 () [with T = int]':
 static_warning.cpp: 24: 17: instanciado desde aquí
 static_warning.cpp: 19: 3: warning: 'void wrap  :: static_warning19 :: _ (const detail :: false_type &) [con T = int]' 
     está en desuso (declarado en static_warning.cpp: 19): malo con 4 y 5 [-Wdeprecated-declarations]

Mientras que Visual C ++ 2010 (at / W3 o superior) dice:

 warnproj.cpp (1): advertencia C4996: 'static_warning1 :: _': Falló con 1 y 2
 warnproj.cpp (1): ver statement de 'static_warning1 :: _'
 warnproj.cpp (6): advertencia C4996: 'Foo :: static_warning6 :: _': 2 y 3: oops
 warnproj.cpp (6): ver statement de 'Foo :: static_warning6 :: _'
 warnproj.cpp (12): advertencia C4996: 'func :: static_warning12 :: _': No tan bueno en 3 y 4
 warnproj.cpp (12): ver statement de 'func :: static_warning12 :: _'
 warnproj.cpp (19): advertencia C4996: 'wrap  :: static_warning19 :: _': malo con 4 y 5
     con
     [
         T = int
     ]
 warnproj.cpp (19): ver la statement de 'wrap  :: static_warning19 :: _'
     con
     [
         T = int
     ]
 warnproj.cpp (19): al comstackr la función de miembro de plantilla de clase 'wrap  :: static_warning19 :: static_warning19 (void)'
     con
     [
         T = int
     ]
 warnproj.cpp (24): ver la referencia a la instanciación de la plantilla de clase 'wrap  :: static_warning19' siendo comstackdo
     con
     [
         T = int
     ]

Clang ++ 3.1 en Linux produce el producto más bonito (color no mostrado):

 tst3.cpp: 1: 1: advertencia: '_' está en desuso: error con 1 y 2
       [-Wdeprecated-declarations]
 STATIC_WARNING (1 == 2, "Falló con 1 y 2");
 ^
 tst3.cpp: 24: 38: nota: ampliado desde la macro 'STATIC_WARNING'
   PP_CAT (static_warning, __ LINE __) () {_ (:: detail :: converter <(cond)> ());} \
                                      ^
 tst3.cpp: 6: 3: advertencia: '_' está en desuso: 2 y 3: ¡Uy!
       [-Wdeprecated-declarations]
   STATIC_WARNING (2 == 3, "2 y 3: oops");
   ^
 tst3.cpp: 24: 38: nota: ampliado desde la macro 'STATIC_WARNING'
   PP_CAT (static_warning, __ LINE __) () {_ (:: detail :: converter <(cond)> ());} \
                                      ^
 tst3.cpp: 12: 3: advertencia: '_' está en desuso: no tan bueno en 3 y 4
       [-Wdeprecated-declarations]
   STATIC_WARNING (3 == 4, "No tan bueno en 3 y 4");
   ^
 tst3.cpp: 24: 38: nota: ampliado desde la macro 'STATIC_WARNING'
   PP_CAT (static_warning, __ LINE __) () {_ (:: detail :: converter <(cond)> ());} \
                                      ^
 tst3.cpp: 19: 3: advertencia: '_' está en desuso: malo con 4 y 5
       [-Wdeprecated-declarations]
   STATIC_WARNING (4 == 5, "Malo con 4 y 5");
   ^
 tst3.cpp: 24: 38: nota: ampliado desde la macro 'STATIC_WARNING'
   PP_CAT (static_warning, __ LINE __) () {_ (:: detail :: converter <(cond)> ());} \
                                      ^
 tst3.cpp: 23: 17: nota: en la instanciación de la función miembro
       'wrap  :: static_warning19 :: static_warning19' solicitado aquí
 plantilla struct wrap 
                 ^
 4 advertencias generadas

Aquí está lo mejor que he encontrado hasta ahora. Es básico y no se ajusta a sus requisitos, pero en su lugar sigue la ruta de BOOST_MPL_ASSERT_MSG porque su mensaje debe tomar la forma de un identificador válido. (Hasta donde yo sé, la única forma en que podría obtener una cadena impresa en el mensaje de advertencia es si la advertencia que usó resultó ser una de las cadenas, e imprimió su contenido).

Requiere la advertencia de que una variable no utilizada esté habilitada. En g ++ esta es -Wunused-variable (habilitada por -Wall ), y en MSVC está advirtiendo C4101 que está habilitada en el nivel de advertencia 3.

Obviamente no está muy probado y podría mejorarse de varias maneras (use __COUNTER__ lugar de __LINE__ en comstackdores compatibles, impresión de mensajes más bonita, use Boost para simplificar, etc.), pero parece hacer el trabajo. Aquí está la placa de la caldera:

 namespace detail { template  struct static_warning; template <> struct static_warning { template  static void warn() {} }; template <> struct static_warning { // If you're here because of a warning, please see where the // template was instantiated for the source of the warning. template  static void warn() { Message STATIC_WARNING_FAILED; } }; } #define STATIC_WARNING_DETAIL_EX(cond, msg, line) \ struct static_warning ## line \ { \ class msg {}; \ \ static_warning ## line() \ { \ ::detail::static_warning<(cond)>:: \ warn(); \ } \ } #define STATIC_WARNING_DETAIL(cond, msg, line) \ STATIC_WARNING_DETAIL_EX(cond, msg, line) // Use these: #define STATIC_WARNING_MSG(cond, msg) \ STATIC_WARNING_DETAIL(cond, msg, __LINE__) #define STATIC_WARNING(cond) \ STATIC_WARNING_DETAIL(cond, STATIC_WARNING_FAILED, __LINE__) 

Y una prueba:

 STATIC_WARNING(sizeof(int) == 2); int main() { STATIC_WARNING_MSG(sizeof(char) != 1, JUST_KIDDING_ALL_IS_WELL); } 

En MSVC esto produce:

 >main.cpp(19): warning C4101: 'STATIC_WARNING_FAILED' : unreferenced local variable > main.cpp(45) : see reference to function template instantiation 'void detail::static_warning::warn(void)' being compiled >main.cpp(19): warning C4101: 'STATIC_WARNING_FAILED' : unreferenced local variable > main.cpp(49) : see reference to function template instantiation 'void detail::static_warning::warn(void)' being compiled 

Y en GCC produce:

 main.cpp: In static member function 'static void detail::static_warning::warn() [with Message = void************ (static_warning39::STATIC_WARNING_FAILED::************)()]': main.cpp:39:1: instantiated from here main.cpp:19:38: warning: unused variable 'STATIC_WARNING_FAILED' main.cpp: In static member function 'static void detail::static_warning::warn() [with Message = void************ (main()::static_warning43::JUST_KIDDING_ALL_IS_WELL::************)()]': main.cpp:43:5: instantiated from here main.cpp:19:38: warning: unused variable 'STATIC_WARNING_FAILED' 

Aquí hay una solución que usa la biblioteca de Boost MPL:

 #include  #include  #include  #define static_warning_impl2(cond, msg, line) \ struct static_warning_ ## line { \ struct msg {}; \ typedef typename boost::mpl::eval_if_c< \ cond, \ boost::mpl::identity, \ boost::mpl::print \ >::type msg ## _; \ } #define static_warning_impl1(cond, msg, line) \ static_warning_impl2(cond, msg, line) #define static_warning(cond, msg) \ static_warning_impl1(cond, msg, __LINE__) 

Viene con la misma restricción que la solución de GMan: el mensaje debe ser un identificador válido. Aquí hay dos pruebas

 static_warning(sizeof(int) == 4, size_of_int_is_not_4); 

y

 static_warning(sizeof(int) == 2, size_of_int_is_not_2); 

Con MSVS 2010, la primera prueba se comstack sin advertencias, la segunda comstack con la advertencia

 C:\Libraries\Boost\boost_1_48_0\boost/mpl/print.hpp(51): warning C4308: negative integral constant converted to unsigned type C:\Libraries\Boost\boost_1_48_0\boost/mpl/eval_if.hpp(63) : see reference to class template instantiation 'boost::mpl::print' being compiled with [ T=static_warning_28::size_of_int_is_not_2 ] Test.cpp(28) : see reference to class template instantiation 'boost::mpl::eval_if_c' being compiled with [ C=false, F1=boost::mpl::identity, F2=boost::mpl::print ] 

El código usa boost :: mpl :: print. De la metaprogtwigción de la plantilla C ++ de D. Abrahams y A. Gurtovoy, página 171:

Para generar un registro de ejecución en tiempo de comstackción, necesitamos una forma de generar un mensaje de diagnóstico: una advertencia. Debido a que no existe una única construcción que cause que todos los comstackdores generen una advertencia (de hecho, la mayoría de los comstackdores le permiten desactivar advertencias por completo), MPL tiene una metafunción de print que es idéntica a la identity excepto que está optimizada para generar una advertencia comstackdores con su configuración habitual.

    Intereting Posts