visual tutorial studio installed descargar c++ c++11 gcc visual-c++ clang

c++ - tutorial - ¿Hay puntos de secuencia en las listas de inicializadores con refuerzos cuando se aplican a los constructores?



where is clang installed (2)

De acuerdo con el documento estándar n4296 C ++:

[dcl.init.list] (8.5.4.4) (pg223-224)

Dentro de la lista inicializadora de una lista iniciada con arriostramiento, las cláusulas inicializadoras, incluidas aquellas que resultan de expansiones de paquetes (14.5.3), se evalúan en el orden en que aparecen. Es decir, cada cálculo de valor y efecto secundario asociado con una cláusula de inicialización dada se secuencia antes de cada cálculo de valor y efecto secundario asociado con cualquier cláusula de inicializador que sigue en la lista separada por comas de la lista de inicializador. [Nota: Este orden de evaluación se mantiene independientemente de la semántica de la inicialización; por ejemplo, se aplica cuando los elementos de la lista de inicializadores se interpretan como argumentos de una llamada de constructor, aunque normalmente no hay restricciones de secuencia en los argumentos de una llamada. "Nota final"

(énfasis mío)

La nota se agregó aquí: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1030

Esto me dice que el siguiente código:

#include <iostream> struct MyType { MyType(int i, int j, int k, int l) : sum(i + j + k + l) { } int sum; }; int main() { int i = 0; std::cout << MyType{ ++i, ++i, ++i, ++i }.sum << ''/n''; }

Debe imprimir "10".

Este es mi razonamiento:

  • MyType se está inicializando a través de una lista iniciada con paréntesis
  • las listas de iniciación se evalúan en orden
  • Incluso cuando se interpreta como argumentos de una llamada de constructor.
  • esto significa que debe ser evaluado como MyType (1,2,3,4)

Es decir, el código anterior debe comportarse exactamente como este código:

#include <initializer_list> #include <iostream> int main() { int i = 0; std::initializer_list<int> il{++i, ++i, ++i, ++i}; std::cout << *il.begin() + *(il.begin() + 1) + *(il.begin() + 2) + *(il.begin() + 3) << ''/n''; }

Pero no lo hace. El primer ejemplo imprime ''16'' y el segundo ejemplo ''10''

Literalmente, todos los compiladores de todos los proveedores pueden obtener impresiones "16", aparentemente ignorando esa parte del estándar y no insertando puntos de secuencia.

¿Que me estoy perdiendo aqui?

Nota: Lo siguiente parece estar relacionado con esta pregunta:


Esta nota no está relacionada con el orden de evaluación. Como se indicó en uno de los comentarios, se trata del orden de conversión de los parámetros reales en valores y el estándar no define dicho orden. Debería recibir la siguiente advertencia (gcc):

17:58: warning: operation on ''i'' may be undefined [-Wsequence-point]

Modifiqué un programa ligeramente para demostrar cómo funciona la evaluación de argumentos con {} y ().

Con dicha modificación, el programa no depende del orden de conversión de lvalue a rvalue, por lo que no tiene una ambigüedad que lo decepcione.

#include <iostream> struct MyType { MyType(int i, int j) : sum(i + j) { } int sum; }; int main() { int i = 0; int a,b; std::cout << MyType{ (a = ++i), (b = ++i) }.sum << ''/n''; std::cout << "Here clauses are evaluated in order they appear: a=" << a << ", b=" << b << std::endl; i = 0; std::cout << MyType( (a = ++i), (b = ++i) ).sum << ''/n''; std::cout << "Here order of evaluation depends on implementation: a=" << a << ", b=" << b << std::endl; }

Y la salida de este programa para clang y gcc:

sonido metálico:

3 Here clauses are evaluated in order they appear: a=1, b=2 3 Here order of evaluation depends on implementation: a=1, b=2

gcc:

3 Here clauses are evaluated in order they appear: a=1, b=2 3 Here order of evaluation depends on implementation: a=2, b=1

Como puede ver, en el caso de los corchetes, las cláusulas se evalúan en orden de aparición en ambos compiladores, que corresponde a la nota que proporcionó.


La respuesta parece ser que sí, este es un error tanto en GCC como en MSVC.

Este es el estado de este problema:

  1. Hay varios errores contra GCC con respecto a las reglas de la lista de inicio. La mayoría de ellos no han sido reconocidos por el equipo de GCC. Esto al menos implica que G ++ tiene errores aquí porque los problemas no se han cerrado como no válidos
  2. Recibí información no oficial del equipo de compilación de MSVC de que esto es, de hecho, un error en su compilador y están trabajando internamente para solucionarlo. Sin embargo, no tengo ningún error externo que señalar. A partir de la actualización 3 de MSVC 2015, el comportamiento anterior permanece.
  3. Clang, que en este punto es, con mucho, el compilador más pedante de quejas de estándares, lo implementa de la manera en que parece leer el estándar.

Mi investigación personal, las discusiones con expertos en C ++ en conferencias y las respuestas no oficiales que recibí de los desarrolladores del compilador indican que se trata de un error en MSVC y GCC, pero siempre me resisto a responder mis propias preguntas sobre . Pero aquí estamos.