J'ai une carte où je voudrais effectuer un appel sur chaque fonction membre d'objet de type de données. Je sais pourtant comment faire cela sur n'importe quelle séquence, mais est-il possible de le faire sur un conteneur associatif?
La réponse la plus proche que j'ai pu trouver était la suivante: Boost.Bind pour accéder à std :: map elements dans std :: for_each . Mais je ne peux pas utiliser boost dans mon projet, existe-t-il une alternative STL qui me manque pour boost :: bind?
Si cela n’était pas possible, je pensais créer une séquence temporaire pour les pointeurs sur les objets de données, puis appeler for_each dessus, comme ceci:
class MyClass
{
public:
void Method() const;
}
std::map<int, MyClass> Map;
//...
std::vector<MyClass*> Vector;
std::transform(Map.begin(), Map.end(), std::back_inserter(Vector), std::mem_fun_ref(&std::map<int, MyClass>::value_type::second));
std::for_each(Vector.begin(), Vector.end(), std::mem_fun(&MyClass::Method));
Ça a l'air trop obscur et je ne l'aime pas vraiment. Aucune suggestion?
Vous pouvez parcourir un objet std::map
. Chaque itérateur indiquera un std::pair<const T,S>
où T
et S
sont les mêmes types que ceux spécifiés sur votre map
.
Ici ce serait:
for (std::map<int, MyClass>::iterator it = Map.begin(); it != Map.end(); ++it)
{
it->second.Method();
}
Si vous souhaitez toujours utiliser std::for_each
, transmettez une fonction qui prend un std::pair<const int, MyClass>&
comme argument.
Exemple:
void CallMyMethod(std::pair<const int, MyClass>& pair) // could be a class static method as well
{
pair.second.Method();
}
Et transmettez-le à std::for_each
:
std::for_each(Map.begin(), Map.end(), CallMyMethod);
C++ 11 vous permet de faire:
for (const auto& kv : myMap) {
std::cout << kv.first << " has value " << kv.second << std::endl;
}
METTRE À JOUR:
const auto est plus sûr si vous ne voulez pas modifier la carte.
Que diriez-vous d'un simple C++? (exemple corrigé d'après la note de @Noah Roberts)
for(std::map<int, MyClass>::iterator itr = Map.begin(), itr_end = Map.end(); itr != itr_end; ++itr) {
itr->second.Method();
}
C++ 14 apporte des lambdas génériques . Cela signifie que nous pouvons utiliser std :: for_each très facilement:
std::map<int, int> myMap{{1, 2}, {3, 4}, {5, 6}, {7, 8}};
std::for_each(myMap.begin(), myMap.end(), [](const auto &myMapPair) {
std::cout << "first " << myMapPair.first << " second "
<< myMapPair.second << std::endl;
});
Je pense que std :: for_each est parfois mieux adapté qu'une simple plage basée sur une boucle. Par exemple, lorsque vous souhaitez uniquement parcourir un sous-ensemble d'une carte.
Il est regrettable que vous n’ayez pas Boost, mais si votre implémentation STL possède des extensions, vous pouvez composer mem_fun_ref et select2nd pour créer un seul foncteur utilisable avec for_each. Le code ressemblerait à ceci:
#include <algorithm>
#include <map>
#include <ext/functional> // GNU-specific extension for functor classes missing from standard STL
using namespace __gnu_cxx; // for compose1 and select2nd
class MyClass
{
public:
void Method() const;
};
std::map<int, MyClass> Map;
int main(void)
{
std::for_each(Map.begin(), Map.end(), compose1(std::mem_fun_ref(&MyClass::Method), select2nd<std::map<int, MyClass>::value_type>()));
}
Notez que si vous n'avez pas accès à compose1 (ou au modèle unary_compose) et à select2nd, ils sont assez faciles à écrire.
Pour les collègues programmeurs qui tombent sur cette question de Google, il existe un bon moyen d’utiliser boost.
Expliqué ici: Est-il possible d'utiliser boost :: foreach avec std :: map?
Exemple concret pour votre commodité:
// typedef in include, given here for info :
typedef std::map<std::string, std::string> Wt::WEnvironment::CookieMap
Wt::WEnvironment::CookieMap cookie_map = environment.cookies();
BOOST_FOREACH( const Wt::WEnvironment::CookieMap::value_type &cookie, cookie_map )
{
std::cout << "cookie : " << cookie.first << " = " << cookie.second << endl;
}
prendre plaisir.
Voici un exemple d'utilisation de for_each pour une carte.
std::map<int, int> map;
map.insert(std::pair<int, int>(1, 2));
map.insert(std::pair<int, int>(2, 4));
map.insert(std::pair<int, int>(3, 6));
auto f = [](std::pair<int,int> it) {std::cout << it.first + it.second << std::endl; };
std::for_each(map.begin(), map.end(), f);
D'après mes souvenirs, la carte C++ peut vous retourner un itérateur de clés à l'aide de map.begin (). Vous pouvez utiliser cet itérateur pour parcourir toutes les clés jusqu'à atteindre map.end () et obtenir la valeur correspondante:. Carte C++
J'ai écrit ceci il y a quelque temps pour faire exactement ce que vous cherchez.
namespace STLHelpers
{
//
// iterator helper type for iterating through the *values* of key/value collections
//
/////////////////////////////////////////////
template<typename _traits>
struct _value_iterator
{
explicit _value_iterator(typename _traits::iterator_type _it)
: it(_it)
{
}
_value_iterator(const _value_iterator &_other)
: it(_other.it)
{
}
friend bool operator==(const _value_iterator &lhs, const _value_iterator &rhs)
{
return lhs.it == rhs.it;
}
friend bool operator!=(const _value_iterator &lhs, const _value_iterator &rhs)
{
return !(lhs == rhs);
}
_value_iterator &operator++()
{
++it;
return *this;
}
_value_iterator operator++(int)
{
_value_iterator t(*this);
++*this;
return t;
}
typename _traits::value_type &operator->()
{
return **this;
}
typename _traits::value_type &operator*()
{
return it->second;
}
typename _traits::iterator_type it;
};
template<typename _tyMap>
struct _map_iterator_traits
{
typedef typename _tyMap::iterator iterator_type;
typedef typename _tyMap::mapped_type value_type;
};
template<typename _tyMap>
struct _const_map_iterator_traits
{
typedef typename _tyMap::const_iterator iterator_type;
typedef const typename _tyMap::mapped_type value_type;
};
}
Ça va fonctionner pour vous ?
class MyClass;
typedef std::pair<int,MyClass> MyPair;
class MyClass
{
private:
void foo() const{};
public:
static void Method(MyPair const& p)
{
//......
p.second.foo();
};
};
// ...
std::map<int, MyClass> Map;
//.....
std::for_each(Map.begin(), Map.end(), (&MyClass::Method));
Juste un exemple:
template <class key, class value>
class insertIntoVec
{
public:
insertIntoVec(std::vector<value>& vec_in):m_vec(vec_in)
{}
void operator () (const std::pair<key, value>& rhs)
{
m_vec.Push_back(rhs.second);
}
private:
std::vector<value>& m_vec;
};
int main()
{
std::map<int, std::string> aMap;
aMap[1] = "test1";
aMap[2] = "test2";
aMap[3] = "test3";
aMap[4] = "test4";
std::vector<std::string> aVec;
aVec.reserve(aMap.size());
std::for_each(aMap.begin(), aMap.end(),
insertIntoVec<int, std::string>(aVec)
);
}