c++ - para - partes de un mapa
Uso de for_each en los elementos del mapa (10)
Tengo un mapa en el que me gustaría realizar una llamada en cada función miembro de tipo de objeto de datos. Todavía sé cómo hacer esto en cualquier secuencia pero, ¿es posible hacerlo en un contenedor asociativo?
La respuesta más cercana que pude encontrar fue la siguiente: Boost.Bind para acceder a los elementos de std :: map en std :: for_each . Pero no puedo usar boost en mi proyecto, entonces, ¿hay una alternativa de STL que me falta para impulsar :: bind?
Si no es posible, pensé en crear una secuencia temporal para los punteros a los objetos de datos y luego, invocar cada uno en él, algo como esto:
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));
Parece demasiado ofuscado y realmente no me gusta. ¿Alguna sugerencia?
¿Qué tal un simple C ++? (ejemplo fijado de acuerdo con la nota de @Noah Roberts)
for(std::map<int, MyClass>::iterator itr = Map.begin(), itr_end = Map.end(); itr != itr_end; ++itr) {
itr->second.Method();
}
C ++ 11 te permite hacer:
for (const auto& kv : myMap) {
std::cout << kv.first << " has value " << kv.second << std::endl;
}
ACTUALIZAR:
const auto es más seguro si no desea modificar el mapa.
C ++ 14 trae genéricos lambdas. Lo que significa que podemos usar std :: for_each muy fácilmente:
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;
});
Creo que std :: for_each a veces es más apropiado que un simple rango basado en loop. Por ejemplo, cuando solo desea recorrer un subconjunto de un mapa.
Es lamentable que no tenga Boost; sin embargo, si su implementación de STL tiene extensiones, puede componer mem_fun_ref y seleccionar2nd para crear un único functor adecuado para usar con for_each. El código se vería así:
#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>()));
}
Tenga en cuenta que si no tiene acceso a compose1 (o la plantilla unary_compose) y selecciona2nd, son bastante fáciles de escribir.
Escribí un momento para hacer exactamente lo que estás buscando.
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;
};
}
Funcionará para ti ?
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));
Para los programadores compañeros que tropiezan con esta pregunta de google, hay una buena forma de usar boost.
Explicado aquí: ¿Es posible usar boost :: foreach con std :: map?
Ejemplo real para su conveniencia:
// 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;
}
disfrutar.
Por lo que recuerdo, el mapa C ++ puede devolverle un iterador de claves usando map.begin (), puede usar ese iterador para recorrer todas las claves hasta que llegue a map.end (), y obtenga el valor correspondiente: mapa C ++
Puede iterar a través de un objeto std::map
. Cada iterador apuntará a std::pair<const T,S>
donde T
y S
son los mismos tipos que especificó en su map
.
Aquí esto sería:
for (std::map<int, MyClass>::iterator it = Map.begin(); it != Map.end(); ++it)
{
it->second.Method();
}
Si aún desea usar std::for_each
, pase una función que toma un std::pair<const int, MyClass>&
como un argumento en su lugar.
Ejemplo:
void CallMyMethod(std::pair<const int, MyClass>& pair) // could be a class static method as well
{
pair.second.Method();
}
Y std::for_each
a std::for_each
:
std::for_each(Map.begin(), Map.end(), CallMyMethod);
Solo un ejemplo:
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)
);
}