Les algorithmes STL sont une chose assez utile en C++. Mais une chose qui m'irrite est qu'ils semblent manquer de composabilité.
Par exemple, disons que j'ai une vector<pair<int, int>>
et je veux le transformer en un vector<int>
contenant uniquement le second
membre de la paire. C'est assez simple :
std::vector<std::pair<int, int>> values = GetValues();
std::vector<int> result;
std::transform(values.begin(), values.end(), std::back_inserter(result),
[] (std::pair<int, int> p) { return p.second; });
Ou peut-être que je veux filtrer les vector
pour seulement les paires dont first
est pair. C'est aussi assez simple :
std::vector<std::pair<int, int>> values = GetValues();
std::vector<std::pair<int, int>> result;
std::copy_if(values.begin(), values.end(), std::back_inserter(result),
[] (std::pair<int, int> p) { return (p.first % 2) == 0; });
Mais que faire si je veux faire les deux ? Il n'y a pas de transform_if
et en utilisant à la fois transform
y copy_if
semble nécessiter l'allocation d'un espace temporaire vector
pour contenir le résultat intermédiaire :
std::vector<std::pair<int, int>> values = GetValues();
std::vector<std::pair<int, int>> temp;
std::vector<int> result;
std::copy_if(values.begin(), values.end(), std::back_inserter(temp),
[] (std::pair<int, int> p) { return (p.first % 2) == 0; });
std::transform(values.begin(), values.end(), std::back_inserter(result),
[] (std::pair<int, int> p) { return p.second; });
Cela me semble plutôt inutile. La seule façon à laquelle je pense pour éviter le vecteur temporaire est d'abandonner transform
y copy_if
et utiliser simplement for_each
(ou une boucle for ordinaire, selon ce qui vous convient le mieux) :
std::vector<std::pair<int, int>> values = GetValues();
std::vector<int> result;
std::for_each(values.begin(), values.end(),
[&result] (std::pair<int, int> p)
{ if( (p.first % 2) == 0 ) result.push_back(p.second); });
Est-ce que je rate quelque chose ? Existe-t-il un bon moyen de composer deux algorithmes STL existants en un nouveau sans avoir besoin de stockage temporaire ?
2 votes
Vous pouvez toujours l'emballer avec votre propre
transform_if
implémentation. Les implémentations de certains algorithmes STL sont aussi simples que quelques boucles, de toute façon, donc vous n'auriez pas de raison de ne pas les intégrer.3 votes
Je préfère faire
for (const auto& value: values) { if ((value.first % 2) == 0) result.push_back(value.second); }
2 votes
Ce genre de code me fait souhaiter qu'il y ait un moyen d'intégrer Haskell dans C++ (ainsi ce code deviendrait simplement
map snd . filter (even . fst)
).