studio programacion para móviles libro edición desarrollo desarrollar curso aprende aplicaciones c++ c++11

programacion - C++ 11 basado en rango para bucles sin variable de bucle



manual de programacion android pdf (9)

En C ++ necesito iterar un cierto número de veces, pero no necesito una variable de iteración. Por ejemplo:

for( int x=0; x<10; ++x ) { /* code goes here, i do not reference "x" in this code */ }

Me doy cuenta de que puedo hacer esto reemplazando el "código va aquí" por una función lambda o nombrada, pero esta pregunta es específicamente sobre bucles.

Esperaba que los bucles foráneos basados ​​en rango de C ++ 11 ayudaran:

for( auto x : boost::irange(0,10) ) { /* code goes here, i do not reference "x" in this code */ }

pero lo anterior da una "variable local sin referencia" ya que nunca referencia explícitamente x.

Me pregunto si existe una manera más elegante de escribir lo anterior para bucles, de modo que el código no genere una advertencia de "variable local sin referencia".


En mi opinión, malgastas el bucle basado en el rango. El ciclo basado en rango se debe usar cuando la lógica es: " para cada elemento de la colección hacer algo ". La idea general es deshacerse de la variable de índice ya que no es importante. Si tiene una colección, debe instrumentarla con las API necesarias para habilitar la iteración basada en el rango. Si no tiene una colección, no tiene ningún negocio para usar el bucle por rango (en realidad, eso es lo que el compilador implica de una manera no tan informativa). En esta situación, un ciclo for / while normal es la elección natural.


No hay forma de hacer un rango basado en el trabajo simplemente iterando sobre varios números.

C ++ 11 bucles basados ​​en el rango requieren una expresión a distancia que puede ser:

  • una matriz o
  • una clase que tiene cualquiera
    • Las funciones de miembro begin() y end() o
    • funciones gratuitas disponibles begin() y end() (a través de ADL)

Además de eso: un rango basado en produce algunos gastos generales:

for ( for_range_declaration : expression ) statement

se expande a

range_init = (expression) { auto && __range = range_init; for ( auto __begin = begin_expr, __end = end_expr; __begin != __end; ++__begin ) { for_range_declaration = *__begin; statement; } }

Donde begin_expr y end_expr se obtienen a través de la inspección de arrays o los pares begin() / end() .

No creo que esto tenga más "limpieza" que un simple for-loop. Especialmente con respecto al rendimiento. Sin llamadas, solo un bucle simple.

La única forma en que puedo averiguar para hacerlo más elegante (donde lo elegante está claramente sujeto a mi opinión) es usar un tamaño o tipo sin signo aquí:

for(size_t x(0U); x<10U; ++x) f();


Podría usar el STL junto con una expresión lambda.

#include <algorithm> #include <iostream> int main() { int a[] = {1,2,3,4,5,6}; std::for_each(std::begin(a), std::end(a), [](int){std::cout << "Don''t care" << std::endl;}); }

Este enfoque también funciona para contenedores arbitrarios como vectores o listas. Deje vector<int> a , luego llamaría a.begin() y a.end() . Tenga en cuenta que también puede usar un puntero a función en lugar de una expresión lambda.

Lo anterior preserva su noción de usar un foreach, sin quejarse de un parámetro no utilizado.


Puede haber una manera de hacerlo, pero dudo que sea más elegante. Lo que tiene en ese primer bucle ya es la forma correcta de hacerlo, limitando el alcance / duración de la variable de bucle.

Simplemente ignoraría la advertencia de variable no utilizada (es solo una indicación del compilador de que algo puede estar mal, después de todo) o usaré las instalaciones del compilador (si están disponibles) para simplemente desactivar la advertencia en ese punto.

Esto puede ser posible con algún tipo de #pragma dependiendo de su entorno, o algunas implementaciones le permiten hacer cosas como:

for (int x = 0; x < 10; ++x) { (void)x; // Other code goes here, that does not reference "x". }

He visto ese truco de void utilizado para los parámetros no utilizados en los cuerpos de las funciones.


Realmente hay una manera de hacer que esto funcione. Todo lo que necesita hacer es devolver un std::array con la longitud especificada por la constante que proporciona:

template <int N> using range = std::array<int, N>; int main() { for (auto x : range<5>()) { std::cout << "Awesome/n"; } }

Salida:

Increíble
Increíble
Increíble
Increíble
Increíble

Aquí hay una demostración.

Nota: Esto supone que el especificador de rango es una constante en tiempo de compilación, por lo que si tiene que usar una variable, asegúrese de que esté marcado como constexpr .


Suponiendo que 10 es una constante de tiempo de compilación ...

#include <cstddef> #include <utility> template<std::size_t N> struct do_N_times_type { template<typename Lambda> void operator()( Lambda&& closure ) const { closure(); do_N_times_type<N-1>()(std::forward<Lambda>(closure)); } }; template<> struct do_N_times_type<1> { template<typename Lambda> void operator()( Lambda&& closure ) const { std::forward<Lambda>(closure)(); } }; template<> struct do_N_times_type<0> { template<typename Lambda> void operator()( Lambda&& closure ) const { } }; template<std::size_t N, typename Lambda> void do_N_times( Lambda&& closure ) { do_N_times_type<N>()( std::forward<Lambda>(closure) ); }; #include <iostream> void f() { std::cout << "did it!/n"; } int main() { do_N_times<10>([&]{ f(); }); }

o solo

int main() { do_N_times<10>(f); }

Otros métodos ridículos:

Escribe un iterador de rango (yo llamo index mina) que produce un rango de tipos de iterador en integral (valor predeterminado para std::size_t ). Luego escribe:

for( auto _:index_range(10) )

que usa una variable ( _ ) pero parece excesivamente confuso.

Otro enfoque loco sería crear un generador tipo pitón. Escribir un envoltorio de generador que tome un rango iterable y produzca una función que devuelva std::optional en el value_type del rango no es complicado.

Entonces podemos hacer:

auto _ = make_generator( index_range(10) ); while(_()) { }

que también crea una variable temporal, y es aún más obtusa.

Podríamos escribir una función de bucle que opera en generadores:

template<typename Generator, typename Lambda> void While( Generator&& g, Lambda&& l ) { while(true) { auto opt = g(); if (!opt) return; l(*opt); } }

que luego llamamos así:

While( make_generator( index_range(10) ), [&](auto&&){ f(); });

pero esto crea algunas variables temporales en la función, y es más ridículo que el anterior, y se basa en las características de C ++ 1y que ni siquiera se han finalizado.

Aquellos en los que mis intentos de crear una forma sin variables de repetir algo 10 veces.

Pero realmente, solo haría el ciclo.

Es casi seguro que puede bloquear la advertencia escribiendo x=x;

O escribe una función

template<typename Unused> void unused( Unused&& ) {}

y llamar unused(x); - se usa la variable x , y su nombre se cae al interior, por lo que el compilador puede no advertirle al respecto en su interior.

Entonces intente esto:

template<typename Unused> void unused( Unused&& ) {} for(int x{};x<10;++x) { unused(x); f(); }

que debería suprimir la advertencia, y ser realmente fácil de entender.


Ya se respondió mejor en https://.com/a/21800058/1147505 : cómo definir una macro SIN USAR que se utilizará en toda la base de código, lo que suprime esta advertencia. De una manera portátil.


esto funciona en GCC y clang y cualquier compilador que admita los atributos de gnu:

for( [[gnu::unused]] auto x : boost::irange(0,10) ) {

y debe compilarse en cualquier compilador de c ++ 11 pero no puede suprimir la advertencia si el compilador no reconoce los atributos de gnu.


Edite ahora con un 100% menos de variables de bucle declaradas.

template <typename F> void repeat(unsigned n, F f) { while (n--) f(); }

Úselo como:

repeat(10, f);

o

repeat(10, [] { f(); });

o

int g(int); repeat(10, std::bind(g, 42));

Véalo en vivo en http://ideone.com/4k83TJ