[boost] Parcourir une map de shared_ptr via for_each & bind

Le
Stephane Wirtel
Bonjour à tous,

Voici quelques jours que j'essaie de comprendre boost::bind,
pour cela, j'ai réalisé un petit exercice à base de vector de pointeur
d'instance, et l'exemple semblait concluant, jusqu'à ce que je commence
à utiliser une map comme container.

Voici le code que j'ai écrit, mais je n'arrive pas à résoudre mon
problème de compilation. Je cherche après un indice pour arriver à mon but.

#include <iostream>
#include <typeinfo>
#include <map>
#include <vector>
#include <functional>
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <typeinfo>
#include <boost/assign/list_of.hpp>

#define DECLARE_ATTRIBUTES_WITH_ACCESSORS(_TYPE,_NAME)
private:
_TYPE m##_NAME;
public:
_TYPE _NAME() { return m##_NAME; }
void _NAME( _TYPE const & value ) { m##_NAME = value; }

class User {
public:
typedef boost::shared_ptr< User > SharedPtr;
typedef std::vector< SharedPtr > Vector;
typedef std::map< std::string, SharedPtr > Map;

public:
User( std::string const & _login ) {
login( _login );
}

std::ostream & print( std::ostream & oss ) {
oss << "login: " << login() << std::endl
;
return oss;
}

DECLARE_ATTRIBUTES_WITH_ACCESSORS(int, age)
DECLARE_ATTRIBUTES_WITH_ACCESSORS(std::string, login)
};

int main( int argc, char ** argv ) {
try {
User::Map users =
boost::assign::map_list_of
( "user1", new User( "user1" ) )
( "user2", new User( "user2" ) )
;

std::for_each(
users.begin(), users.end(),
boost::bind(
&User::print,
boost::bind( &User::Map::value_type::second, _1 ),
boost::ref( std::cout )
)
);

/* std::for_each( users.begin(), users.end(), boost::bind(
&User::print, _1, boost::ref( std::cout ) ) ); */
}
catch( std::exception const & ex ) {
std::cerr << "exception: " << ex.what() << std::endl;
}
return 0;
}


Merci pour vos conseils.
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Michael DOUBEZ
Le #311526
Bonjour à tous,

Voici quelques jours que j'essaie de comprendre boost::bind,
pour cela, j'ai réalisé un petit exercice à base de vector de pointeur
d'instance, et l'exemple semblait concluant, jusqu'à ce que je commence
à utiliser une map comme container.

Voici le code que j'ai écrit, mais je n'arrive pas à résoudre mon
problème de compilation. Je cherche après un indice pour arriver à mon but.

#include <iostream>
#include <typeinfo>
#include <map>
#include <vector>
#include <functional>
#include #include #include <typeinfo>
#include
#define DECLARE_ATTRIBUTES_WITH_ACCESSORS(_TYPE,_NAME)
private:
_TYPE m##_NAME;
public:
_TYPE _NAME() { return m##_NAME; }
void _NAME( _TYPE const & value ) { m##_NAME = value; }



Peut être NAME_ devrait être renvoyé en const ref ?
const _TYPE& _NAME() const { return m##_NAME; }


class User {
public:
typedef boost::shared_ptr< User > SharedPtr;
typedef std::vector< SharedPtr > Vector;
typedef std::map< std::string, SharedPtr > Map;

public:
User( std::string const & _login ) {
login( _login );
}

std::ostream & print( std::ostream & oss ) {
oss << "login: " << login() << std::endl
;
return oss;
}

DECLARE_ATTRIBUTES_WITH_ACCESSORS(int, age)
DECLARE_ATTRIBUTES_WITH_ACCESSORS(std::string, login)
};

int main( int argc, char ** argv ) {
try {
User::Map users > boost::assign::map_list_of
( "user1", new User( "user1" ) )
( "user2", new User( "user2" ) )
;

std::for_each(
users.begin(), users.end(),
boost::bind(
&User::print,
boost::bind( &User::Map::value_type::second, _1 ),
boost::ref( std::cout )
)
);


Pour autant que je sache, tu ne peux pas faire de bind sur les variables
membres. Il te faut un accessor:

template < class Pair>
typename Pair::second_type& pair_second(Pair& p)
{
return p.second;
}

puis:
std::for_each(
users.begin(), users.end(),
boost::bind(
&User::print,
boost::bind( &pair_second<User::Map::value_type>, _1 ),
boost::ref( std::cout )
)
);


(Pas essayé mais ça doit marcher)

Sinon, essaye:

std::for_each(
users.begin(), users.end(),
boost::bind(
boost::bind(&User::print,boost::ref( std::cout ),_2),
boost::bind(&pair_second<User::Map::value_type>, _1 )
)
);




/* std::for_each( users.begin(), users.end(), boost::bind(
&User::print, _1, boost::ref( std::cout ) ) ); */
}
catch( std::exception const & ex ) {
std::cerr << "exception: " << ex.what() << std::endl;
}
return 0;
}


Merci pour vos conseils.


Michael

Stephane Wirtel
Le #311525
Peut être NAME_ devrait être renvoyé en const ref ?
const _TYPE& _NAME() const { return m##_NAME; }
Concernant les macros, c'était à la va-vite pour pouvoir me préoccuper

surtout sur l'utilisation de boost::bind

Pour autant que je sache, tu ne peux pas faire de bind sur les variables
membres. Il te faut un accessor:
D'après l'ouvrage "Beyond the C++ Standard Library - An introduction to

Boost" de Björn Karlsson, il est tout à fait possible de le faire sans
aucuns soucis.

D'ailleurs si tu enlèves mon shared_ptr pour le data_type de ma map,
cela fonctionne sans problèmes.

template < class Pair>
typename Pair::second_type& pair_second(Pair& p)
{
return p.second;
}

puis:
std::for_each(
users.begin(), users.end(),
boost::bind(
&User::print,
boost::bind( &pair_second<User::Map::value_type>, _1 ),
boost::ref( std::cout )
)
);


(Pas essayé mais ça doit marcher)

Sinon, essaye:

std::for_each(
users.begin(), users.end(),
boost::bind(
boost::bind(&User::print,boost::ref( std::cout ),_2),
boost::bind(&pair_second<User::Map::value_type>, _1 )
)
);

Merci pour ton aide, mais j'ai essayé avec la fonction templatée et sans

( en utilisant le binding de variables membres ) et le résultat est
toujours un soucis de compilation.

Par contre, peux-tu m'expliquer un peu l'idée derrière le second code
que tu m'as fait parvenir ?

std::for_each(
users.begin(), users.end(),
boost::bind(
boost::bind(&User::print,boost::ref( std::cout ),_2),
boost::bind(&pair_second<User::Map::value_type>, _1 )
)
);


Merci

Stéphane

Michael DOUBEZ
Le #311524
Peut être NAME_ devrait être renvoyé en const ref ?
const _TYPE& _NAME() const { return m##_NAME; }
Concernant les macros, c'était à la va-vite pour pouvoir me préoccuper

surtout sur l'utilisation de boost::bind

Pour autant que je sache, tu ne peux pas faire de bind sur les
variables membres. Il te faut un accessor:
D'après l'ouvrage "Beyond the C++ Standard Library - An introduction to

Boost" de Björn Karlsson, il est tout à fait possible de le faire sans
aucuns soucis.



Ok. C'est bon à savoir.

D'ailleurs si tu enlèves mon shared_ptr pour le data_type de ma map,
cela fonctionne sans problèmes.



Tu veux dire en utilisant un pointeur ?


Par contre, peux-tu m'expliquer un peu l'idée derrière le second code
que tu m'as fait parvenir ?

std::for_each(
users.begin(), users.end(),
boost::bind(
boost::bind(&User::print,boost::ref( std::cout ),_2),
boost::bind(&pair_second<User::Map::value_type>, _1 )
)
);


Rien de bien extraordinaire, le binding est fait en deux temps au lieu
d'un. J'ai pas une grande habitude de boost.bind alors des fois je suis
prudent dans son utilisation.

Michael


Stephane Wirtel
Le #311523
Tu veux dire en utilisant un pointeur ?
Oui, tout à fait.


Encore merci,

Michael DOUBEZ
Le #311522
Bonjour à tous,

Voici quelques jours que j'essaie de comprendre boost::bind,
pour cela, j'ai réalisé un petit exercice à base de vector de pointeur
d'instance, et l'exemple semblait concluant, jusqu'à ce que je commence
à utiliser une map comme container.

Voici le code que j'ai écrit, mais je n'arrive pas à résoudre mon
problème de compilation. Je cherche après un indice pour arriver à mon but.

#include <iostream>
#include <typeinfo>
#include <map>
#include <vector>
#include <functional>
#include #include #include <typeinfo>
#include
#define DECLARE_ATTRIBUTES_WITH_ACCESSORS(_TYPE,_NAME)
private:
_TYPE m##_NAME;
public:
_TYPE _NAME() { return m##_NAME; }
void _NAME( _TYPE const & value ) { m##_NAME = value; }

class User {
public:
typedef boost::shared_ptr< User > SharedPtr;
typedef std::vector< SharedPtr > Vector;
typedef std::map< std::string, SharedPtr > Map;

public:
User( std::string const & _login ) {
login( _login );
}

std::ostream & print( std::ostream & oss ) {
oss << "login: " << login() << std::endl
;
return oss;
}

DECLARE_ATTRIBUTES_WITH_ACCESSORS(int, age)
DECLARE_ATTRIBUTES_WITH_ACCESSORS(std::string, login)
};

int main( int argc, char ** argv ) {
try {
User::Map users > boost::assign::map_list_of
( "user1", new User( "user1" ) )
( "user2", new User( "user2" ) )
;

std::for_each(
users.begin(), users.end(),
boost::bind(
&User::print,
boost::bind( &User::Map::value_type::second, _1 ),


Je suis truffe. Il ne doit pas y avoir de spécialisation
bind()(shared_ptr<>()&)

Le code suivant fonctionne sous g++:

std::for_each(
users.begin(), users.end(),
boost::bind(
&User::print,
boost::bind(&User::SharedPtr::get,boost::bind(
&User::Map::value_type::second, _1 )),
boost::ref( std::cout )
)
);


boost::shared_ptr<T>() n'a pas de cast automatique vers T*.


boost::ref( std::cout )
)
);

/* std::for_each( users.begin(), users.end(), boost::bind(
&User::print, _1, boost::ref( std::cout ) ) ); */
}
catch( std::exception const & ex ) {
std::cerr << "exception: " << ex.what() << std::endl;
}
return 0;
}


Merci pour vos conseils.


Michael

Stephane Wirtel
Le #311481
Merci Michael,

Je suis truffe. Il ne doit pas y avoir de spécialisation
bind()(shared_ptr<>()&)

Le code suivant fonctionne sous g++:

std::for_each(
users.begin(), users.end(),
boost::bind(
&User::print,
boost::bind(&User::SharedPtr::get,boost::bind(
&User::Map::value_type::second, _1 )),
boost::ref( std::cout )
)
);
'ai essayé ton code et cela semble fonctionner sans problème.


J'ai essayé ton exemple et cela fonctionne.


boost::shared_ptr<T>() n'a pas de cast automatique vers T*.


Mais j'ai tout de même une question, si tu regardes le code qui est en
commentaire, j'utilisais un User::Vector comme container, et ce code
fonctionnait parfaitement sous g++. Et comme tu as pû le constater, mon
User::Vector est vecteur de shared_ptr, donc, semblerait-il qu'il y ait
tout ce qui est nécessaire pour résoudre ce problème de manière plus
élégante ?

/* std::for_each( users.begin(), users.end(), boost::bind( &User::print, _1, boost::ref( std::cout ) ) ); */




Qu'en penses-tu ?

Stéphane

Encore merci pour ton exemple


Mathias Gaunard
Le #311480

#define DECLARE_ATTRIBUTES_WITH_ACCESSORS(_TYPE,_NAME)
private:
_TYPE m##_NAME;
public:
_TYPE _NAME() { return m##_NAME; }
void _NAME( _TYPE const & value ) { m##_NAME = value; }

class User {
public:
typedef boost::shared_ptr< User > SharedPtr;
typedef std::vector< SharedPtr > Vector;
typedef std::map< std::string, SharedPtr > Map;

public:
User( std::string const & _login ) {
login( _login );
}

std::ostream & print( std::ostream & oss ) {
oss << "login: " << login() << std::endl
;
return oss;
}

DECLARE_ATTRIBUTES_WITH_ACCESSORS(int, age)
DECLARE_ATTRIBUTES_WITH_ACCESSORS(std::string, login)
};

int main( int argc, char ** argv ) {
try {
User::Map users > boost::assign::map_list_of
( "user1", new User( "user1" ) )
( "user2", new User( "user2" ) )
;

std::for_each(
users.begin(), users.end(),
boost::bind(
&User::print,
boost::bind( &User::Map::value_type::second, _1 ),
boost::ref( std::cout )
)



Avec lambda, tu peux pas tout simplement mettre un * devant pour
résoudre le problème ?

Stephane Wirtel
Le #311479
Avec lambda, tu peux pas tout simplement mettre un * devant pour
résoudre le problème ?


pas encore essayé, mais je n'étais qu'à boost::bind, je vais y regarder.

Merci de l'indice

Michael DOUBEZ
Le #311477
Merci Michael,

Je suis truffe. Il ne doit pas y avoir de spécialisation
bind()(shared_ptr<>()&)
boost::shared_ptr<T>() n'a pas de cast automatique vers T*.


Mais j'ai tout de même une question, si tu regardes le code qui est en
commentaire, j'utilisais un User::Vector comme container, et ce code
fonctionnait parfaitement sous g++. Et comme tu as pû le constater, mon
User::Vector est vecteur de shared_ptr, donc, semblerait-il qu'il y ait
tout ce qui est nécessaire pour résoudre ce problème de manière plus
élégante ?

/* std::for_each( users.begin(), users.end(), boost::bind(
&User::print, _1, boost::ref( std::cout ) ) ); */



Tu as raison. Le problème viens de la valeur retournée par le binding de

membre.

Le code suivant fonctionne:

std::for_each(
users.begin(), users.end(),
boost::bind(
&User::print,
boost::bind<User::SharedPtr&>(
&User::Map::value_type::second, _1 ),
boost::ref( std::cout )
)
);


Michael



Stephane Wirtel
Le #311476
Tu as raison. Le problème viens de la valeur retournée par le binding de
membre.

Le code suivant fonctionne:

std::for_each(
users.begin(), users.end(),
boost::bind(
&User::print,
boost::bind<User::SharedPtr&>(
&User::Map::value_type::second, _1 ),
boost::ref( std::cout )
)
);


Michael


Merci, cela fonctionne nickel, et effectivement cela me semble moins

redondant dans le code.

Dommage qu'il n'y ait pas une FAQ avec ce genre d'exercice.

Stéphane

Publicité
Poster une réponse
Anonyme