Je ne connaissais pas la version boost. J'avais déjà écrit un adaptateur qui fonctionne, lorsque je suis tombé sur cette question-réponse. Je faisais des recherches sur Stackoverflow pour voir si je pouvais comprendre pourquoi le compilateur MS n'est pas satisfait à moins que j'utilise des types de retour de fin pour begin() et end(). Voici le code qui fonctionne :
#include <string>
#include <iostream>
template<class Fwd>
struct Reverser {
const Fwd &fwd;
Reverser<Fwd>(const Fwd &fwd_): fwd(fwd_) {}
auto begin() -> decltype(fwd.rbegin()) const { return fwd.rbegin(); }
auto end() -> decltype(fwd.rend()) const { return fwd.rend(); }
};
template<class Fwd>
Reverser<Fwd> reverse(const Fwd &fwd) { return Reverser<Fwd>(fwd); }
int main() {
using namespace std;
string str = ".dlrow olleH";
for(char c: reverse(str)) cout << c;
cout << endl;
}
UPDATE : En voici un meilleur.
template<class Fwd>
struct Reverser_generic {
Fwd &fwd;
Reverser_generic(Fwd& fwd_): fwd(fwd_) {}
typedef std::reverse_iterator<typename Fwd::iterator> reverse_iterator;
reverse_iterator begin() { return reverse_iterator(std::end(fwd)); }
reverse_iterator end() { return reverse_iterator(std::begin(fwd)); }
};
template<class Fwd >
struct Reverser_special{
Fwd &fwd;
Reverser_special(Fwd& fwd_): fwd(fwd_) {}
auto begin() -> decltype(fwd.rbegin()){ return fwd.rbegin(); }
auto end() ->decltype(fwd.rbegin()) { return fwd.rend(); }
};
template<class Fwd>
auto reverse_impl(Fwd& fwd, long) -> decltype( Reverser_generic<Fwd>(fwd)){
return Reverser_generic<Fwd>(fwd);
}
template<class Fwd>
auto reverse_impl(Fwd& fwd, int)
-> decltype(fwd.rbegin(), Reverser_special<Fwd>(fwd))
{
return Reverser_special<Fwd>(fwd);
}
template<class Fwd>
auto reverse( Fwd&& fwd) -> decltype(reverse_impl(fwd,int(0))) {
static_assert(!(is_rvalue_reference<Fwd&&>::value),
"Cannot pass rvalue_reference to dj::reverse()");
return reverse_impl(fwd,int(0));
}
19 votes
Un adaptateur de conteneur inversé, cela semble intéressant, mais je pense que vous devrez l'écrire vous-même. Nous n'aurions pas ce problème si le comité de normalisation se dépêchait d'adapter des algorithmes basés sur des plages au lieu d'itérateurs explicites.
0 votes
@Seth Je sais que je pourrais l'écrire, mais ce n'est pas la question. Si je l'écris, elle devient une de ces fonctions utilitaires qui n'ont pas leur place quelque part en particulier (tm), donc vous finissez par saupoudrer votre code avec l'inclusion d'un tel en-tête utilitaire et vous mélangez votre système de construction pour le partager entre les projets. Selon ce raisonnement, nous devrions toujours utiliser BOOST_FOREACH au lieu de range-for. Et oui, je suis paresseux.
5 votes
@deft_code : "au lieu de ?" Pourquoi voudriez-vous vous débarrasser des algorithmes basés sur les itérateurs ? Ils sont bien meilleurs et moins verbeux pour les cas où vous n'itérez pas à partir de
begin
aend
ou pour traiter les itérateurs de flux et autres. Les algorithmes d'intervalle seraient parfaits, mais ils ne sont en fait que du sucre syntaxique (à l'exception de la possibilité d'une évaluation paresseuse) par rapport aux algorithmes d'itérateurs.18 votes
@deft_code
template<typename T> class reverse_adapter { public: reverse_adapter(T& c) : c(c) { } typename T::reverse_iterator begin() { return c.rbegin(); } typename T::reverse_iterator end() { return c.rend(); } private: T& c; };
Il peut être amélioré (en ajoutantconst
versions, etc.) mais cela fonctionne :vector<int> v {1, 2, 3}; reverse_adapter<decltype(v)> ra; for (auto& i : ra) cout << i;
imprime321
10 votes
@SethCarnegie : Et pour ajouter une belle forme fonctionnelle :
template<typename T> reverse_adapter<T> reverse_adapt_container(T &c) {return reverse_adapter<T>(c);}
Donc, vous pouvez simplement utiliserfor(auto &i: reverse_adapt_container(v)) cout << i;
pour itérer.1 votes
Même si la boucle for basée sur l'intervalle est définie comme itérant consécutivement à partir de
begin
aend
Je pense que sémantiquement, cela signifie que l'ordre des opérations n'est pas important.2 votes
Je ne pense pas que ce soit le cas. debe Je ne veux pas dire cela, car cela la rendrait indisponible en tant que syntaxe concise pour les boucles où l'ordre est important. J'estime que la concision est plus importante/utile que le sens sémantique, mais si vous n'accordez pas d'importance à la concision, votre guide de style peut lui donner les implications que vous souhaitez. C'est un peu ce que
parallel_for
serait pour, avec une condition "Peu importe l'ordre" encore plus forte, si elle était incorporée dans la norme sous une forme ou une autre. Bien sûr, il pourrait aussi avoir un sucre syntaxique basé sur l'intervalle :-)