4
votes

C ++ répéter N itérations

Je peux clairement faire quelque chose comme ceci:

std::repeat(10000, testIteration);

Mais y a-t-il des fonctions std qui font une chose similaire sur une ligne? Quelque chose comme ça:

for(int i = 0; i < 10000; i++)
    testIteration();


7 commentaires

En C ++ 11? Non, il n'y a rien. Je devrais probablement être en mesure de faire quelque chose avec les plages C ++ 20 et std :: for_each . Jusqu'à ce que C ++ 20 soit disponible et commun, vous pouvez utiliser la bibliothèque de plages qui est la base pour les plages C ++ 20.


Si vous utilisez une boucle pour appliquer une opération à chaque élément d'un conteneur, il existe des algorithmes standard. Mais, pour répéter essentiellement une fonction, appelez un nombre arbitraire de fois ... c'est à cela que servent les constructions de boucle, et la bibliothèque standard essaie rarement de répliquer ce qui peut être plus facilement fait en utilisant les fonctionnalités du langage. Si vous voulez vraiment une telle fonction, lancez-la vous-même - n'essayez simplement pas de la mettre dans l'espace de noms std (car cela donnera un comportement non défini).


Le nouveau std :: for_each et même la nouvelle syntaxe for sont là pour aider à réduire la plaque chauffante qui était fréquemment requise. Ici cependant, il en résultera en fait PLUS de plaque chauffante en règle générale. Prenons le cas où la fonction que vous souhaitez appeler est une fonction membre d'une classe; on ne peut trivialement pas simplement passer le pointeur de fonction comme vous l'avez ici.


C'est un cas où l'OMI il est très peu probable que cette boucle soit supérieure à la lisibilité.


Eh bien, 1 / vous devriez vraiment utiliser une boucle pour cela; 2 / il y a std :: for_each_n mais c'est non implémenté dans gcc ni clang; 3 / C ++ 20 plages pourraient être une solution; 4 / rappel de 1 /.


Pouvez-vous utiliser Boost? Il y a Boost counting_range et Boost irange.


La seule fois où j'ai voulu écrire quelque chose comme ça, c'est quand j'essaie de faire des analyses comparatives. Si c'est ce que vous essayez de faire, consultez peut-être github.com/google/benchmark . En tant que cadre, il est plus facile de gérer l'appel d'une fonction suffisamment de fois pour obtenir des résultats significatifs, etc. (Si ce n'est pas ce que vous essayez de faire, n'hésitez pas à m'ignorer - mais je prédis que vous prévoyez de mettre une "heure de début" et une "heure de fin" autour de cela.


5 Réponses :


4
votes

Non, il n'y a pas d'algorithme dans la bibliothèque standard pour faire cela (du moins rien qui ne nécessiterait pas d'écrire un passe-partout inutile). Comme d'autres l'ont déjà mentionné, une boucle est le moyen le plus lisible et le moins obscur de faire "quelque chose" n fois.

Cela étant dit, si vous le prenez comme un exercice pour obtenir une syntaxe plus concise, vous pourriez écrivez ceci:

#include <iostream>
struct my_counter {    
    int stop;
    struct iterator {
        int count;    
        iterator& operator++() { ++count; return *this; }
        int operator*() { return count;}
        bool operator!=(const iterator& other) { return count != other.count; }
    };
    iterator begin() { return {0}; }
    iterator end() { return {stop};}    
};

void print() { std::cout << "x"; }

int main() {
     for (auto x : my_counter{5}) print();
}

Cependant, je déconseille fortement d'utiliser quelque chose comme ça. Tout le monde sait comment fonctionne une boucle et ce qu'elle fait. Étant habitué aux boucles for, vous pouvez lire une boucle for en un clin d'œil, alors que tout le reste est inhabituel, surprenant et obscur, à moins qu'il n'y ait un algorithme standard bien sûr (bien que je doute qu'un algorithme pour ce cas particulier soit d'une grande utilité) . Pourquoi réinventer la roue quand vous pouvez utiliser une boucle?


8 commentaires

Pourquoi? Parallélisme!


@DavidHParry pourquoi quoi? désolé, aucune idée de ce à quoi vous faites référence


Vous avez clairement demandé "... pourquoi réinventer la roue quand vous pouvez utiliser une boucle?" et je vous ai répondu.


@DavidHParry comment est-ce une réponse? Cela explique autant que. Pourquoi? Pâtes! : P. Sérieusement, je ne vois pas comment l'un est meilleur que l'autre en ce qui concerne le parallélisme


Regardez la relation entre std :: execution :: * et les bibliothèques STD en C ++. Vous êtes les bienvenus.


@DavidHParry il n'y a pas d'algorithme std qui fait ce que op veut, donc je ne vois pas comment les algorithmes standard ayant une politique d'exécution aident à décider entre une boucle for et un algorithme écrit à la main non parallèle, les deux peuvent être parallélisés aussi bien / mauvais


@DavidHParry également, il n'y a pas de parallélisme dans l'exemple OP, mais une fonction qui a évidemment des effets secondaires (sinon toute la boucle est un noop), donc je préfère supposer que l'ordre compte (c'est-à-dire pas de parallélisation)


@DavidHParry J'ai corrigé le dernier paragraphe, peut-être que ma mauvaise ponctuation a causé un malentendu



10
votes

Dans la norme proposée pour C ++ 20 , il y a un exemple pour iota_view :

for (int _ : view::iota{0, 10})
    testIteration();            // calls testIteration 10 times.

Mais pour l'instant, range- La bibliothèque v3 peut être utilisée:

for (int i : iota_view{1, 10})
  cout << i << ' '; // prints: 1 2 3 4 5 6 7 8 9


0 commentaires

2
votes

Personnellement, j'aime utiliser une petite fonction d'aide pour faire cela.

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

int main() {

   repeat(1000, [&] {
      testIteration();
   });
}

Cela évite d'avoir à épeler le nom d'une variable. Je préfère utiliser view :: iota quand j'ai besoin d'un nom.

Cela étant dit, on me dit que c'est déroutant à lire, et que tout le monde peut lire une boucle for, donc c'est probablement la voie à suivre. (À moins que la fonction ne soit placée dans std :: bien sûr).


0 commentaires

0
votes

Qu'en est-il simplement de la définition d'une macro? #define FOR (N, foo, ...) for (int _i = 0; _i

Par exemple.

hello 18
hello 18
hello 18
hello 18
hello 18

Sortie :

#include <iostream>

#define FOR(N, foo, ...) for (int _i = 0; _i < N; _i++) foo(__VA_ARGS__);

void bar(int a, int b)
{
    std::cout << "hello " << a+b << std::endl;
}

int main()
{
    FOR(5, bar, 12, 6);
    return 0;
}


0 commentaires

0
votes

Juste pour référence, il y a std :: generate et std :: generate_n qui peuvent être utilisés, mais uniquement pour l'initialisation du tableau en faisant quelque chose comme ceci: < pré> XXX


0 commentaires