Considérez Comment écrire un pipeline de plage utilisant des conteneurs temporaires?. La question est de savoir comment construire une vue transformant chaque élément T
à l'aide d'une fonction donnée
std::vector f(T t);
tout en étant conforme à la restriction (en empruntant la réponse principale là-bas) que
Une vue est un wrapper léger qui présente une vue d'une séquence sous-jacente d'éléments de manière personnalisée sans la muter ni la copier. Les vues sont bon marché à créer et à copier, et possèdent une sémantique de référence sans propriétaire.
En gros, toutes les réponses là-bas semblent être d'accord pour dire que, en raison de cette restriction, cela ne peut pas être fait via une vue.
Je ne comprends pas comment cela s'intègre dans la bibliothèque prenant en charge partial_sum
.
Considérez l'entier glorifié suivant:
#include
#include
#include
#include
using namespace ranges;
struct glorified_int {
explicit glorified_int(int i) : m_i{std::make_shared(i)} {}
operator int() const { return *m_i; }
std::shared_ptr m_i;
};
glorified_int operator+(const glorified_int &lhs, const glorified_int &rhs) {
glorified_int ret{(int)lhs + (int)rhs};
return ret;
}
Cela emballe essentiellement un int
dans une classe le stockant dans un std::shared_ptr
, permettant d'initialiser, d'extraire et d'ajouter. En ce qui concerne la sémantique de référence sans propriétaire, je ne vois pas de différence fondamentale entre cela et un conteneur tel que std::vector
.
La plage ne semble pas avoir de problème à appliquer partial_sum
à cela, cependant:
int main() {
std::vector vi{ glorified_int{1}, glorified_int{2} };
for(const auto &ps: vi | view::partial_sum())
std::cout << ps << std::endl;
Affiche
$ ./a.out
1
3
N'est-ce pas (l'entier glorifié) 3 un temporaire ici? Il ne fait certainement pas partie de la séquence d'origine. De plus, une somme partielle est une transformation avec état, évidemment, alors comment la plage peut-elle garantir que
Les vues sont bon marché à créer et à copier, et possèdent une sémantique de référence sans propriétaire.
La vue est aussi coûteuse à copier que l'objet d'accumulation.
Remarquez qu'il n'y a aucun problème à chaîner cela plus loin (c'est-à-dire, ce n'est pas une action):
vi | view::partial_sum() | view::take(10);
Quelle est alors la différence?
Code complet
#include
#include
#include
#include
using namespace ranges;
struct glorified_int {
explicit glorified_int(int i) : m_i{std::make_shared(i)} {}
operator int() const { return *m_i; }
std::shared_ptr m_i;
};
glorified_int operator+(const glorified_int &lhs, const glorified_int &rhs) {
glorified_int ret{(int)lhs + (int)rhs};
return ret;
}
int main() {
std::vector vi{ glorified_int{1}, glorified_int{2} };
for(const auto &ps: vi | view::partial_sum())
std::cout << ps << std::endl;
vi | view::partial_sum() | view::take(10);
}