c++ - compiler - gnuc
Manejo de la advertencia de noexcept de gcc (3)
El problema sobre el que te advierten es que en C ++ 14, esto funcionará:
void call(void (*f)())
{
f();
}
void func() noexcept {}
int main(int argc, char* argv[])
{
call(&func);
return 0;
}
pero en C ++ 17, necesitaría cambiar la declaración de call
para ser:
void call(void (*f)() noexcept)
{
f();
}
Ya que ha definido la call
para ser una plantilla, no necesita preocuparse por esto. Aún así, podría causarle problemas porque el tipo inferido está cambiando, lo que generalmente no sucede.
Por ejemplo, este código se compilará en C ++ 14 pero no en C ++ 17:
void foo() noexcept {}
void bar() {}
template <typename F>
void call(bool b, F f1, F f2)
{
if (b)
f1();
else
f2();
}
void foobar(bool b)
{
call(b, &foo, &bar);
}
En C ++ 14, los tipos de foo
y bar
son los mismos, pero son diferentes en C ++ 17, lo que significa que la resolución de la plantilla fallará. El mensaje de error en gcc 7.2 con el indicador -std=c++1z
es:
note: template argument deduction/substitution failed:
note: deduced conflicting types for parameter ''F'' (''void (*)() noexcept'' and ''void (*)()'')
En el ejemplo que has dado, no hay problema y no tendrás problemas compilando en el modo C ++ 14 o C ++ 17. Si el código es más complejo que el ejemplo aquí (por ejemplo, similar a los ejemplos que he dado anteriormente), podría encontrar algunos problemas con el compilador. Parece que tienes un compilador reciente; intente compilar con -std=c++1z
y vea si hay advertencias o errores.
Considere este ejemplo, del error 80985 :
template <class Func>
void call(Func f)
{
f();
}
void func() noexcept { }
int main()
{
call(func);
}
Compilando esto con todas las advertencias habilitadas, como lo hace, produce:
$ g++ -std=c++14 -Wall foo.cxx
foo.cxx:2:6: warning: mangled name for ‘void call(Func) [with Func = void (*)() noexcept]’ will change in C++17 because the exception specification is part of a function type [-Wnoexcept-type]
void call(Func f)
^~~~
¿Qué se supone que debo hacer exactamente con esta advertencia? ¿Cuál es la solución?
Estoy subestimando la respuesta de Ross para la solución de la call<void (*)()>(func)
. Le dice explícitamente al compilador que desea que se noexcept
una instancia de la plantilla para un tipo de función no- noexcept
, y garantiza que su código operará exactamente igual en C ++ 17 que en C ++ 14.
Más alternativas son:
(1) Envuelva la función noexcept
en un lambda (que no es noexcept
):
template <class Func>
void call(Func f)
{
f();
}
void func() noexcept { }
int main()
{
call([]() { func(); });
}
(2) Cree una función de envoltura separada sin noexcept
. Inicialmente, esto es más tipeo, pero si tiene varios sitios de llamadas, podría guardar el tecleado en general. Esto es lo que terminé haciendo en el código que originalmente me pidió que presentara el error GCC.
Hay varias cosas que puedes hacer sobre el mensaje de advertencia.
Deshabilítelo con el -Wno-noexcept-type
. En muchos proyectos, el mensaje de advertencia es inútil porque no hay posibilidad de que el objeto resultante se vincule con otro objeto que espera que utilice el nombre de C ++ 17 de GCC. Si no está compilando con configuraciones diferentes -std=
y no está construyendo una biblioteca estática o compartida donde la función ofensiva es parte de su interfaz pública, entonces el mensaje de advertencia puede desactivarse de manera segura.
Compila todo tu código con -std=c++17
. El mensaje de advertencia desaparecerá, ya que la función utilizará el nuevo nombre mutilado.
Hacer la función static
. Dado que otro archivo de objeto ya no puede hacer referencia a la función mediante una modificación diferente de la función, no se mostrará el mensaje de advertencia. La definición de la función deberá incluirse en todas las unidades de compilación que la utilizan, pero para las funciones de plantilla como en su ejemplo, esto es común de todos modos. Además, esto no funcionará para las funciones miembro, ya que las funciones static
significan otra cosa.
Al llamar a una plantilla de función, especifique el parámetro de la plantilla dando explícitamente un tipo de puntero de función compatible que no tiene la especificación de excepción. Por ejemplo, call<void (*)()>(func)
. También debería poder usar cast para hacer esto también, pero GCC 7.2.0 sigue generando una advertencia aunque el uso de -std=c++17
no cambie el problema.
Cuando la función no es una plantilla, no utilice noexcept
con ningún tipo de puntero de función utilizado en el tipo de función. Este y el último punto se basan en el hecho de que solo los tipos de punteros de función no lanzadores dan como resultado cambios de denominación de funciones y que los punteros de función no lanzadores pueden asignarse (C ++ 11) o convertirse implícitamente (C ++ 17) para lanzar punteros de función.