for_each for devc dev c++ c++11 for-loop gcc visual-c++

devc - for auto p m c++



Rango basado en bucle con variable existente (4)

Usando un rango basado en bucle en C ++ 11 con una variable existente, esperaría que esa variable se llene con el valor de la última iteración después del bucle. Sin embargo, he obtenido resultados diferentes cuando lo probé.

Ejemplo:

#include <iostream> #include <vector> using namespace std; int main() { std::vector<int> v; v.push_back(2); v.push_back(43); v.push_back(99); int last = -50; for (last : v) std::cout << ":" << last << "/n"; std::cout << last; return 0; }

  1. MSVC 2013 no parece admitir el rango basado en bucles sin declaración de tipo
  2. GCC-5.1 introduce automáticamente una nueva variable o la vuelve a establecer en el valor inicial, dando

    : 2
    : 43
    : 99
    -50

Supongo que MSVC solo está siendo MSVC de nuevo, pero ¿qué hay de GCC aquí? ¿Por qué el last no es 99 en la última línea?

Dada la definición de la norma , esperaría el comportamiento que describí en la primera oración.

{ auto && __range = range_expression ; for (auto __begin = begin_expr, __end = end_expr; __begin != __end; ++__begin) { range_declaration = *__begin; loop_statement } }

range_declaration siendo el last y no el int last , esto debería modificar la variable existente.


De acuerdo con el estándar, un rango basado en bucle produce la misma salida que:

{ auto&& __range = expression; for (auto __begin = begin-expression, __end = end-expression; __begin != __end; ++__begin) { declaration = *__begin; statement } }

Como puede ver, la variable de iteración __begin se está definiendo en su propio ámbito.

¿Por qué el último no es 99 en la última línea?

Tienes dos variables llamadas last . Uno está en el alcance de su función principal y tiene el valor -50 . La segunda variable se define en el alcance del rango basado en bucle.

Dentro del bucle, la impresión de la last variable imprime la desde el mismo ámbito (es decir, desde el rango basado en bucle). Sin embargo, después del bucle, la last impresión volverá a imprimir la variable desde el mismo ámbito, que es el que contiene -50


GCC implementó la propuesta de normas n3994 , que sugiere que for (elem : range) sea ​​azúcar sintáctico para for (auto&& elem : range) . Esto no se convirtió en C ++ 17, por lo que la funcionalidad se ha eliminado de las versiones más recientes de GCC.

La variable nombrada utilizada para iterar sobre el rango debe ser una declaración de acuerdo con [stmt.ranged] , por lo que su código no debe compilarse.


Su código no se compila a partir de gcc 6.1 (y para todas las versiones de clang):

main.cpp:12:8: error: range-based for loop requires type for loop variable for (last : v) ^ auto &&

Parece que las versiones anteriores usaron auto implícitamente aquí. El hecho de que obtenga -50 como última salida se debe for introduce el alcance local para el último, por lo tanto, después for fines, se usó el último desde el alcance externo.

Hice un poco de excavación y esto fue a propósito bajo gcc: n3994 , que en breve está haciendo lo siguiente:

A range-based for statement of the form for ( for-range-identifier : for-range-initializer ) statement is equivalent to for ( auto&& for-range-identifier : for-range-initializer ) statement

luego no llegó a c ++ 17 y se eliminó aquí:

https://gcc.gnu.org/viewcvs/gcc?view=revision&revision=229632


Tu programa no compila con mi g ++ 4.9.2.

Compile con clang ++ 3.5 (con una advertencia: "basado en rango para bucle con tipo deducido implícito es una extensión de C ++ 1z [-Wc ++ 1z-extensions]")

Pero clang ++ usa diferentes last variables

Con el siguiente programa modificado

#include <iostream> #include <vector> using namespace std; int main() { std::vector<int> v; v.push_back(2); v.push_back(43); v.push_back(99); int last = -50; std::cout << "extern last pointer: " << long(&last) << ''/n''; for ( last : v) { std::cout << ": " << last << " ; pointer: " << long(&last) << ''/n''; } std::cout << "extern last pointer again: " << long(&last) << ''/n''; std::cout << ": " << last << std::endl; return 0; }

Obtengo la siguiente salida

extern last pointer: 140721376927168 : 2 ; pointer: 38101008 : 43 ; pointer: 38101012 : 99 ; pointer: 38101016 extern last pointer again: 140721376927168 : -50