65 votes

Boucles for C ++11 basées sur la plage sans variable de boucle

En C++, j'ai besoin de réitérer un certain nombre de fois, mais je n'ai pas besoin d'une variable d'itération. Par exemple:

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

Je me rends compte que je peux le faire par le remplacement de "code se trouve ici" avec un lambda ou un nom de fonction, mais cette question est spécifiquement pour les boucles.

J'espérais que le C++11 de gamme à base de boucles permettrait de:

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

mais le ci-dessus donne un "non référencé à la variable locale" depuis que j'ai jamais explicitement référence à x.

Je me demandais si il existe un moyen plus élégant d'écrire ci-dessus pour les boucles de sorte que le code ne génère pas un "non référencé à la variable locale" avertissement.

48voto

sehe Points 123151

Editez maintenant avec 100% moins de variables de boucle déclarées.

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

Utilisez-le comme:

 repeat(10, f);
 

ou

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

ou

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

Voir en direct sur http://ideone.com/4k83TJ

22voto

paxdiablo Points 341644

Il peut y avoir un moyen de le faire , mais je doute fort que ce serait plus élégant. Ce que vous avez dans cette première boucle est déjà la bonne façon de le faire, en limitant la portée / durée de vie de la variable de boucle.

J'ignorerais simplement l'avertissement de variable inutilisée (c'est seulement une indication du compilateur que quelque chose peut être faux, après tout) ou j'utilise les fonctionnalités du compilateur (si disponibles) pour simplement désactiver l'avertissement à cet endroit.

9voto

Yakk Points 31636

En supposant 10 est une compilation constante de temps...

#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();
  });
}

ou tout simplement

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

D'autres ridicule méthodes:

Écrire une série d'itérateur (j'ai appeler le mien index) qui produit une gamme de itérateur sur les types intégraux (j'ai par défaut std::size_t). Puis tapez:

for( auto _:index_range(10) )

qui utilise une variable (_), mais semble extrêmement déroutant.

Un autre fou approche serait de créer un python-comme générateur. L'écriture d'un générateur de wrapper qui prend un objet iterable gamme et produit une fonction qui retourne l' std::optional sur le value_type de la gamme n'est pas difficile.

Nous pouvons alors faire:

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

ce qui crée une variable temporaire, et est même le plus obtus.

Nous pourrions écrire une boucle de la fonction qui opère sur les générateurs:

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

nous appelons alors comme:

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

mais cette fois, crée des variables temporaires dans la fonction, et est encore plus ridicule que le précédent, et s'appuie sur les fonctionnalités de C++1y qui n'a pas encore été finalisé.

Ceux où mes tentatives pour créer une variable, à moins de répéter quelque chose 10 fois.

Mais vraiment, je venais de faire la boucle.

Vous pouvez presque certainement bloquer l'avertissement en tapant x=x;

Ou écrire une fonction

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

et appelez - unused(x); -- la variable x est utilisé, et son nom est tombée à l'intérieur, de sorte que le compilateur ne peut pas vous avertir à ce sujet à l'intérieur.

Donc, essayez ceci:

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

ce qui devrait supprimer l'avertissement, et être facile à comprendre.

9voto

0x499602D2 Points 36421

Il ya effectivement un moyen de faire ce travail. Tout ce que vous devez faire est de retourner un std::array à la longueur spécifiée par la constante de vous fournir:

template <int N>
using range = std::array<int, N>;

int main()
{
    for (auto x : range<5>())
    {
        std::cout << "Awesome\n";
    }
}

Sortie:

Génial
Génial
Génial
Génial
Génial

Voici une démo.

Remarque: C'est en supposant que la gamme spécificateur est une constante de compilation, donc, si vous devez utiliser une variable assurez-vous qu'il est valablement marquée constexpr.

4voto

Pixelchemist Points 3636

Il n'y a pas moyen de faire une large base de travail pour simplement une itération sur plusieurs numéros.

C++11 gamme à base de boucles besoin d'un variait expression qui peut être:

  • un tableau ou
  • une classe ayant
    • Les fonctions de membres begin() et end() ou
    • disponible gratuitement fonctions begin() et end() (via ADL)

En plus de cela: Une gamme à base de produit frais généraux:

for ( for_range_declaration : expression ) statement

se développe pour

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

Où begin_expr et end_expr sont obtenues par l'intermédiaire de la matrice de l'inspection ou de l' begin() / end() paires.

Je ne pense pas que ce ne soit plus "propre" qu'une simple boucle for. Surtout à l'égard de la performance. Pas d'appels, juste une simple boucle.

La seule façon que je peux comprendre pour le rendre plus élégant (où l'élégance est clairement soumis à mon avis) est d'utiliser une taille ou d'un type non signé ici:

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X