with initialize argument c++ arrays language-lawyer initializer-list aggregate-initialization

argument - c++ initialize class with parameters



¿Puedo hacer referencia a miembros anteriores de una lista de inicializadores? (1)

Entonces, lo que tenemos aquí es la inicialización agregada cubierta en la sección 8.5.1 del borrador del estándar C ++ y dice:

Un agregado es una matriz o una clase [...]

y:

Cuando un agregado se inicializa mediante una lista de inicializadores, como se especifica en 8.5.4, los elementos de la lista de inicializadores se toman como inicializadores para los miembros del agregado, al aumentar el subíndice o el orden de los miembros. Cada miembro se inicializa con copia desde la cláusula inicializadora correspondiente [...]

Aunque parece razonable que los efectos secundarios de la inicialización de cada miembro del agregado se deban secuenciar antes del siguiente, ya que cada elemento en la lista de inicializadores es una expresión completa. La norma no garantiza realmente esto, podemos ver esto en el informe de defectos 1343 que dice:

La redacción actual no indica que la inicialización de un objeto que no es de clase es una expresión completa, pero presumiblemente debería hacerlo.

y también notas:

La inicialización agregada también podría implicar más de una expresión completa, por lo que la limitación anterior a la "inicialización de un objeto que no es de clase" no es correcta.

y podemos ver en un tema relacionado de discusión estándar que Richard Smith dice:

[intro.execution] p10: "Una expresión completa es una expresión que no es una subexpresión de otra expresión. [...] Si se define una construcción de lenguaje para producir una llamada implícita de una función, un uso de la construcción de lenguaje se considera como una expresión para los propósitos de esta definición ".

Dado que una lista iniciada con paréntesis no es una expresión, y en este caso no resulta en una llamada de función, 5 y si son expresiones completas separadas. Entonces:

[intro.execution] p14: "Cada cálculo de valor y efecto secundario asociado con una expresión completa se secuencia antes de cada cálculo de valor y efecto secundario asociado con la siguiente expresión completa que se evaluará".

Entonces, la única pregunta es, ¿el efecto secundario de la inicialización si "se asocia con" la evaluación de la expresión completa "5"? Creo que la única suposición razonable es que si: 5 estuvieran inicializando un miembro del tipo de clase, la llamada al constructor obviamente sería parte de la expresión completa según la definición en [intro.execution] p10, por lo que es natural suponer que lo mismo es cierto para los tipos escalares.

Sin embargo, no creo que la norma en realidad lo diga explícitamente en ninguna parte.

Por lo tanto, actualmente el estándar no lo especifica y no se puede confiar en él, aunque me sorprendería que una implementación no lo haya tratado de la manera que usted espera.

Para un caso simple como este, algo similar a esto parece una mejor alternativa:

constexpr int value = 13 ; const int foo[2] = {value, value+42};

Cambios en C ++ 17

La propuesta P0507R0: Cuestión básica 1343: la secuenciación de la inicialización no de clase aclara el punto de expresión completa que se menciona aquí pero no responde la pregunta sobre si el efecto secundario de la inicialización se incluye en la evaluación de la expresión completa. Así que no cambia que esto no esté especificado.

Los cambios relevantes para esta pregunta están en [intro.execution] :

Una expresión constituyente se define de la siguiente manera:

(9.1) - La expresión constituyente de una expresión es esa expresión.

(9.2) - Las expresiones constitutivas de una lista de iniciaciones braceadas o de una lista de expresiones (posiblemente entre paréntesis) son expresiones constituyentes de los elementos de la lista respectiva.

(9.3) - Las expresiones constituyentes de un inicializador con corsé o igual de la cláusula form = initializer son las expresiones constituyentes de la cláusula initializer. [Ejemplo:

struct A { int x; }; struct B { int y; struct A a; }; B b = { 5, { 1+1 } };

Las expresiones constituyentes del inicializador utilizado para la inicialización de b son 5 y 1 + 1 . —En ejemplo]

y [intro.execution]p12 :

Una expresión completa es

(12.1) - un operando no evaluado (Cláusula 8),

(12.2) - una expresión constante (8.20),

(12.3) - un declarador de inicio (Cláusula 11) o un inicializador de mem (15.6.2), incluidas las expresiones constituyentes del inicializador,

(12.4) - una invocación de un destructor generado al final de la vida útil de un objeto que no sea un objeto temporal (15.2), o

(12.5) - una expresión que no es una subexpresión de otra expresión y que de otra manera no es parte de una expresión completa.

Entonces, en este caso, tanto 13 como foo[0] + 42 son expresiones constituyentes que forman parte de una expresión completa . Esto es una ruptura con el análisis aquí que planteó que cada uno sería su propia expresión completa.

Cambios en C ++ 20

La propuesta de Inicialización Designada: P0329 contiene la siguiente adición que parece hacer esto bien definido:

Agregue un nuevo párrafo a 11.6.1 [dcl.init.aggr]:

Las inicializaciones de los elementos del agregado se evalúan en el orden de los elementos. Es decir, todos los cálculos de valores y efectos secundarios asociados con un elemento dado se secuencian antes que los de cualquier elemento que lo siga en orden.

Podemos ver que esto se refleja en el último proyecto de norma .

Digamos que quiero referirme a un miembro de una lista de initializer_list que ya definí. ¿Puedo hacerlo?

Este código compila y da lo esperado: "13 55" tanto en Visual Studio como en gcc , solo me gustaría saber que es legal:

const int foo[2] = {13, foo[0] + 42};