#1 Le 16/10/2011, à 05:02
- heudeubert
(c++)problème avec boost::iterator_adaptor
Bonjour !
J'essaie d'utiliser boost::iterator_adaptor, mais j'ai quelques soucis.
Mon premier problème :
#include <boost/iterator_adaptors.hpp>
#include <algorithm>
#include <iostream>
template <class T>
class Reverse : public boost::iterator_adaptor <Reverse<T>, T>
{
public:
Reverse( T IterTemp ) : Reverse<T>::iterator_adaptor_( IterTemp ) {};
void increment( void )
{ --this->base_reference(); }
};
Je n'ai défini qu'increment(void), et non increment(int), decrement, etc. pour simplifier l'example, mais les définir donne le même résultat.
Quand je fais :
int main(void)
{
int oh[] = { 3, 5, 7 };
Reverse <int*> ItoBegin( oh + 2 ), ItoEnd( oh - 1 );
std::copy( ItoBegin, ItoEnd, std::ostream_iterator<int>( std::cout, "\n" ) );
return 0;
}
Et que j'exécute :
$ g++ -Wall -o test test.cpp
$ ./test
Je n'ai pas d'erreur de compilation ni runtime, mais je n'obtient pas d'output. Tandis qu'avec :
void fonc( int a )
{ std::cout << a << "\n"; }
int main(void)
{
int oh[] = { 3, 5, 7 };
Reverse <int*> ItoBegin( oh + 2 ), ItoEnd( oh - 1 );
std::for_each( ItoBegin, ItoEnd, fonc );
return 0;
}
J'obtiens :
7
5
3
Comment cela se fait-il ?
Mon deuxième problème :
J'instancie mon Reverse via :
Reverse( T IterTemp ) : Reverse<T>::iterator_adaptor_( IterTemp ) {};
parce que j'ai vu que cela semblait marcher. Cependant, je me demande pourquoi cette ligne est nécessaire. En effet, dans la définition d'iterator_adaptor dans <boost/iterator/iterator_adaptor.hpp>, on trouve :
template <
class Derived
, class Base
... >
class iterator_adaptor
... {
...
public:
...
explicit iterator_adaptor(Base const &iter)
: m_iterator(iter)
{
}
...
private:
Base m_iterator;
};
Or, quand j'essaie de retirer le constructor Reverse( T IterTemp ), pensant que le constructor ci-dessus suffira, j'obtiens :
...: In function ‘int main()’:
...:21:34: error: no matching function for call to ‘Reverse<int*>::Reverse(int*)’
...:7:1: note: candidates are: Reverse<int*>::Reverse()
...:7:1: note: Reverse<int*>::Reverse(const Reverse<int*>&)
Comme si le compilateur ignorait l'existence du constructor iterator_adaptor(Base const&iter), ou considérait que Base a pour type Reverse<int*>& et non int*.
Comment cela se fait-il ?
Merci beaucoup !
Dernière modification par heudeubert (Le 16/10/2011, à 05:04)
Hors ligne
#2 Le 20/10/2011, à 12:19
- heudeubert
Re : (c++)problème avec boost::iterator_adaptor
Problème 1 résolu :
Reverse<T> est considéré comme un itérateur random access, puisque T (int*) est random access. En conséquence, copy() calcule la distance entre ItoBegin et ItoEnd avec "ItoEnd - ItoBegin" (il s'agit d'une optimisation : avec un iterator non-random access, copy effectue ce calcul via une succession de ++). Il faut donc définir distance_to(), en plus d'incrément() :
typename boost::iterator_traits<Reverse<T> >::difference_type distance_to( const Reverse<T>& Other ) const
{ return this->base_reference() - Other.base_reference(); }
En gros, ma classe Reverse<T> faisaient de fausses assomptions sur le template (-> que T soit au maximum bidirectionnel, et pas random access).
Problème 2 (encore non résolu) :
J'ai réussi à le réduire à :
#include <boost/iterator_adaptors.hpp>
template <class T>
struct Reverse : public boost::iterator_adaptor <Reverse<T>, T>
{
Reverse( T IterTemp ) : Reverse<T>::iterator_adaptor_( IterTemp ) {};
};
int main(void)
{
int oh[] = { 10, 20, 30 };
Reverse<int*> Iter( oh );
return 0;
}
Le problème est que je ne comprends pas pourquoi je dois rajouter "Reverse( T IterTemp ) : ... {};", dans la mesure où l'header définit déjà un constructor prenant un argument T (cf plus haut). J'ai l'impression que cela a à voir avec le fait que le premier élément du template de Reverse est son propre type ("Curiously Recurring Template Pattern (CRTP)"), ce qui perturbe le compilateur, mais j'aimerais réussir à mieux comprendre cette idée.
Merci
Hors ligne
#3 Le 20/10/2011, à 21:35
- Le Farfadet Spatial
Re : (c++)problème avec boost::iterator_adaptor
Salut à tous !
assomptions
L’assomption est le privilège en vertu duquel la Vierge Marie a été transportée au ciel dès la fin de sa vie terrestre. Je doute que cela ait un quelconque rapport ici. Sinon, l’anglais « assumption » se traduit en français par « hypothèse » ou « supposition ».
Oui, j’étais déjà un partisan de maître Capello avant, mais depuis mon retour des États-Unis, je suis devenu un intégriste anti anglicisme !
Le problème est que je ne comprends pas pourquoi je dois rajouter "Reverse( T IterTemp ) : ... {};", dans la mesure où l'header définit déjà un constructor prenant un argument T (cf plus haut). J'ai l'impression que cela a à voir avec le fait que le premier élément du template de Reverse est son propre type ("Curiously Recurring Template Pattern (CRTP)"), ce qui perturbe le compilateur, mais j'aimerais réussir à mieux comprendre cette idée.
Bon, je reconnais avoir regardé un peu vite (et avoir un peu bêtement bloqué sur « assomption »), mais le message d’erreur me faisait plutôt penser à un problème entre type constant et type variable. Sinon, je ne comprends pas bien pourquoi cela te semble étrange d’avoir des prototypes homogènes. Je dois rater quelque chose…
À bientôt.
Le Farfadet Spatial
Hors ligne