sintaxis que por parametros inicializar funciones ejemplos definen defecto declaracion como c++ default-constructor noexcept

que - parametros por defecto c++



= por defecto en declaración vs definición (2)

El comportamiento se trata en [dcl.fct.def.default]p3 que dice:

Si una función que tiene un valor predeterminado explícito se declara con un noexcept-specifier que no produce la misma especificación de excepción que la declaración implícita (18.4), entonces

(3.1) - si la función está predeterminada por defecto en su primera declaración, se define como eliminada;

(3.2) - de lo contrario, el programa está mal formado.

Tenga en cuenta los cambios de redacción en C ++ 20, pero la intención es la misma para este caso. Me parece que la redacción de C ++ 17 es más fácil de asimilar.

Por ejemplo dado:

struct S { S( S&& ) noexcept(false) = default; };

El constructor de movimiento se define como eliminado ya que se debe a [except.spec]p7 :

Un constructor declarado implícitamente para una clase X , o un constructor sin un especificador noexcept predeterminado en su primera declaración, tiene una especificación de excepción de lanzamiento potencial si y solo si cualquiera de las siguientes construcciones es potencialmente de lanzamiento :

(7.1) - un constructor seleccionado por resolución de sobrecarga en la definición implícita del constructor para la clase X para inicializar un subobjeto potencialmente construido, o

(7.2) - una subexpresión de dicha inicialización, como una expresión de argumento predeterminada, o,

(7.3): para un constructor predeterminado, un inicializador de miembro predeterminado.

Ninguno de los casos es válido.

Si volvemos a [dcl.fct.def.default] p3 dice que de lo contrario el programa está mal formado . Los programas mal formados requieren un diagnóstico, por lo que si modificamos el primer ejemplo de la siguiente manera ( véalo en vivo ):

struct S { S( S&& ) noexcept(false) ; private: int i; }; S::S( S&&) noexcept(false) = default ;

producirá un diagnóstico por ejemplo:

error: function ''S::S(S&&)'' defaulted on its redeclaration with an exception-specification that differs from the implicit exception-specification ''noexcept'' S::S( S&&) noexcept(false) = default ; ^

Tenga en cuenta el error relacionado con este caso , parece que no están siguiendo el Informe de defectos 1778 .

Es posible que desee anotar la declaración de una función como predeterminada después de su primera declaración que cubre algunos problemas de optimización / interfaz.

Sé que en lugar de escribir:

class A { public: A(A&&) noexcept = default; };

Uno debería escribir mejor

class A { public: A(A&&) noexcept; }; inline A::A(A&&) noexcept = default;

Las razones que he escuchado son:

  1. Evita que el constructor se deleted . El compilador dará un error si no puede definir la función.

  2. El constructor de movimiento se declara noexcept incluso si algunos de los constructores de movimiento de los campos miembros no están anotados con noexcept .

¿Podría alguien explicar un poco más sobre la teoría detrás de las diferencias?


Solo se utiliza la declaración para describir la clase / método, por lo que al hacer

class A { public: A(A&&) noexcept; };

Incluso puede implementar A::A(A&&) como desee (la definición puede estar en diferentes TU)

Cuando lo implementas con:

A::A(A&&) noexcept = default;

El compilador tiene que generar el método (no puede saber si se elimina de forma implícita, ya que existe un método preciso de declaración), y proporciona un diagnóstico si no puede.

Pero cuando lo declaras dentro de la clase:

class A { public: A(A&&) noexcept = default; };

Es "parte" de la declaración. por lo tanto, podría eliminarse implícitamente (debido a un miembro o clase base).

Lo mismo se aplica para noexcept .

Otra ventaja de poner definición en TU dedicada, es que la definición de dependencias requeridas puede estar solo en esa TU, en lugar de cada lugar donde se generará el método. (Útil para el lenguaje pimpl por ejemplo).

Una desventaja de la definición y declaración dividida es que el método ahora es "proporcionado por el usuario", que puede afectar los rasgos como trivially_constructible / copyable / ...