c++ - plusplus - ¿Por qué el especificador "noexcept" no forma parte del tipo de función?
c++17 (2)
Compatibilidad C / C ++ 03
Una de las ideas básicas más importantes de C ++ es la compatibilidad con versiones anteriores del lenguaje C y versiones anteriores de C ++. Y funciona en la mayoría de los casos. Agregar excepciones a los especificadores de funciones negaría esta idea. No había ninguna noexcept
en C ++ 03 y C y causaría problemas con los punteros de función, etc.
Nivel bajo
Vamos a pensar cómo funciona la función en el nivel bajo. Básicamente se saltan con la dirección de retorno guardada (en la pila). Pasan argumentos y devuelven valores también a través de la pila (no siempre, pero simplifiquemos un poco). Entonces, cuando declara una función, realmente indica cuántos bytes debe tomar la función de la pila y cuántos deja en ella. La declaración de la función es sobre todo decirle al programa qué ESPERAR NORMALMENTE de la función. Ahora, sabiendo eso, ¿las excepciones cambian algo en la información que normalmente se pasa a / desde la función? Ellos no Y creo que esta es la razón principal por la que las excepciones no son parte del tipo.
Editar: En C ++ 17, noexcept
convirtió en parte del sistema de tipos, por lo que no puede hacer esto:
void (*p)();
void (**pp)() noexcept = &p; //error here
La razón detrás de esta decisión es, por lo que sé, permitir una mejor optimización.
No entiendo porque No creo que la compatibilidad deba ser un problema, ya que las funciones declaradas sin el especificador realmente lo tienen implícitamente definido como falso. Si se trata de manipulación de nombres, podemos suponer que el antiguo (existente) implicará noexcept (false) y añadir otro nuevo símbolo a la modificación de noexcept (true).
Esto será útil cuando se trabaje con plantillas, ya que ahora el tipo de función de comparación y el especificador noexcept se deben hacer por separado. Lo que básicamente quiero decir es esto:
int func() noexcept(true), func_1() noexcept(false);
decltype(func) == decltype(func_1); //this now equals true
Pero, por otro lado, si tuviéramos una asignación de función utilizando el puntero o la referencia, el especificador noexcept se verifica como si fuera parte del tipo:
int (&refFunc)() noexcept(true) = func_1; //target exception specification is not superset of source
int (&refFunc)() noexcept(true) = func; //ok
Por lo tanto, por ahora, la implementación de la concordancia de funciones completa se debe realizar mediante la comprobación de tipo y noexcept, que es algo compleja:
decltype(func) == decltype(func_1) && noexcept(func()) == noexcept(func_1()); //this now equals false
Imagina si las funciones tienen parámetros:
int func(int, double) noexcept(true), func_1(int, double) noexcept(false);
decltype(func) == decltype(func_1) && noexcept(func(int{}, double{})) == noexcept(func_1(int{}, double{})); //this now equals false
A partir de C ++ 17, el especificador noexcept
es una parte del tipo de función.
La especificación noexcept es una parte del tipo de función y puede aparecer como parte de cualquier declarador de función. (desde C ++ 17)