2
votes

Existe-t-il une fonction de type STL pour remplir un tableau avec une fonction de l'index?

En C ++, nous avons des fonctions comme std :: fill ou std :: fill_n qui sont des moyens pratiques à une ligne de remplir des tableaux de pointeurs, des vecteurs, std :: array et autres conteneurs avec des valeurs. Certains conteneurs ont également leurs propres méthodes fill pour permettre le remplissage avec une valeur constante. Il existe également les fonctions std :: generate {_n} et std :: iota , dont la première permet de remplir les éléments à l'aide d'une fonction générateur et la seconde remplit

Ce que je recherche, c'est une solution similaire - de préférence une solution à une ligne et définie dans la bibliothèque standard - qui permet de remplir le conteneur avec une fonction de l'index. Par exemple, ce serait une solution pour un tableau:

std::array<int, 100> arr;
for (std::size_t i = 0; i < 100; i++)
    arr[i] = f(i);

f (std :: size_t i) est une fonction de l'index.

Existe-t-il une manière intégrée de faire cela?


3 commentaires

pourquoi n'utilisez-vous pas std :: generate_n? c'est exactement ce que tu veux


c'est ce que tu veux? wandbox.org/permlink/tAwaouhYJtacJNjt


@Oblivion Ce serait une solution, cependant, je recherche quelque chose de plus générique qui ne repose pas sur des variables statiques. Par exemple, une fonction qui accepte une expression lambda.


5 Réponses :


6
votes

Vous pouvez utiliser un lambda avec état:

std::array<int, 100> arr;   
std::generate(arr.begin(), arr.end(), [i = std::size_t(0)]() mutable {return f(i++);});

Mais je pense que cela rend le code plus complexe qu'il ne devrait l'être. Utiliser une boucle simple peut être la meilleure option.


0 commentaires

1
votes

Si vous parcourez toujours tout le tableau, vous n'avez même pas besoin d'utiliser de fonction stl, utilisez simplement la boucle de plage:

#include <algorithm>
std::array<int, 100> arr;
int idx = 0;
std::for_each(begin(arr), end(arr), [&idx](int &n){ n = f(idx++); });

Une autre option consiste à utiliser for_each (cela peut être plus utile, si à l'avenir vous voulez remplir votre tableau seulement partiellement )

std::array<int, 100> arr;
int idx = 0;
for (auto& item : array)
    item = f(idx++);

Malheureusement, dans les deux cas , vous devez avoir une variable distincte pour l'index (ici: idx)


0 commentaires

2
votes

Pensez à écrire votre propre modèle de fonction de type STL , apply_idx_func () , pour cela:

100 101 102 103 104 105 106 107 108 109

À titre d'exemple:

auto main() -> int {
   std::array<int, 10> arr;

   // just adds 100 to the index
   auto func = [](size_t idx) -> int {
      return 100 + idx;
   };

   apply_idx_func(std::begin(arr), std::end(arr), func);

   for (auto elem: arr)
      std::cout << elem << ' ';
   std::cout << '\n';
}

Le résultat est:

template<typename FwdItor, typename F>
void apply_idx_func(FwdItor first, FwdItor last, F f) {
   for (size_t idx = 0; first != last; ++first, ++idx)
      *first = f(idx);
}


2 commentaires

Y a-t-il une recommandation de «où» pour mettre l'extension personnalisée? Par exemple quel espace de noms?


@HerpDerpington, vous pouvez créer votre propre espace de noms, par exemple: namespace xtd {...} ( xtd signifierait eXtended sTandarD , contrairement à l'espace de noms std ).



1
votes
std::transform(
    arr.begin(),
    arr.end(),
    boost::irange(0,arr.size()),
    [](const auto& val,const auto& index){return f(index);}
);

0 commentaires

3
votes

Je n'ai pas pu essayer cela avec un compilateur car je ne pouvais pas en trouver un avec des plages C ++ 20, mais quelque chose comme ça devrait fonctionner une fois que les compilateurs les ont implémentés:

auto const values = std::views::iota{1, arr.size()+1} | std::views::transform(f);

ou, si vous voulez juste la séquence de valeurs générées, créez simplement une plage de celles-ci avec

std::ranges::transform(std::views::iota{1, arr.size()+1}, arr, f);

Jusqu'à ce que vous ayez un compilateur C ++ 20, vous pouvez utiliser l'une des bibliothèques de plages , par exemple dans Boost ou Gamme Eric Nieblers-v3


2 commentaires

Si la destination doit vraiment être un std :: array , une étape manque cependant: convertir la vue en tableau.


même pas gcc.godbolt.org ne semble le savoir, c'est aussi nouveau :( gcc.godbolt.org/ z / pgh7uS