2012-02-09 13 views
22

Quiero eliminar elementos (bins histograma) de un std::unordered_map (histograma), que cumple una predictate (bins histograma que tienen recuento cero) dados como una expresión lambda de la siguienteeliminar elementos de un mapa sin ordenar Cumpliendo un predicado

std::remove_if(begin(m_map), end(m_map), [](const Bin & bin) { return bin.second == 0; }); 

pero GCC-4.6.1 se queja de la siguiente manera

/usr/include/c++/4.6/bits/stl_pair.h:156:2: error: assignment of read-only member ‘std::pair<const unsigned char, unsigned char>::first’ 
/usr/include/c++/4.6/bits/stl_pair.h: In member function ‘std::pair<_T1, _T2>& std::pair<_T1, _T2>::operator=(std::pair<_T1, _T2>&&) [with _T1 = const unsigned char, _T2 = long unsigned int, std::pair<_T1, _T2> = std::pair<const unsigned char, long unsigned int>]’: 
/usr/include/c++/4.6/bits/stl_algo.h:1149:13: instantiated from ‘_FIter std::remove_if(_FIter, _FIter, _Predicate) [with _FIter = std::__detail::_Hashtable_iterator<std::pair<const unsigned char, long unsigned int>, false, false>, _Predicate = pnw::histogram<V, C, H>::pack() [with V = std::vector<unsigned char>, C = long unsigned int, H = std::unordered_map<unsigned char, long unsigned int, std::hash<unsigned char>, std::equal_to<unsigned char>, std::allocator<std::pair<const unsigned char, long unsigned int> > >]::<lambda(const Bin&)>]’ 
tests/../histogram.hpp:68:13: instantiated from ‘void pnw::histogram<V, C, H>::pack() [with V = std::vector<unsigned char>, C = long unsigned int, H = std::unordered_map<unsigned char, long unsigned int, std::hash<unsigned char>, std::equal_to<unsigned char>, std::allocator<std::pair<const unsigned char, long unsigned int> > >]’ 
tests/../histogram.hpp:85:13: instantiated from ‘void pnw::histogram<V, C, H>::normalize(uint) [with V = std::vector<unsigned char>, C = long unsigned int, H = std::unordered_map<unsigned char, long unsigned int, std::hash<unsigned char>, std::equal_to<unsigned char>, std::allocator<std::pair<const unsigned char, long unsigned int> > >, uint = unsigned int]’ 
tests/../histogram.hpp:121:51: instantiated from ‘H& pnw::histogram<V, C, H>::add(It, It) [with It = __gnu_cxx::__normal_iterator<const unsigned char*, std::vector<unsigned char> >, V = std::vector<unsigned char>, C = long unsigned int, H = std::unordered_map<unsigned char, long unsigned int, std::hash<unsigned char>, std::equal_to<unsigned char>, std::allocator<std::pair<const unsigned char, long unsigned int> > >]’ 
tests/../histogram.hpp:129:55: instantiated from ‘H& pnw::histogram<V, C, H>::add(const V&) [with V = std::vector<unsigned char>, C = long unsigned int, H = std::unordered_map<unsigned char, long unsigned int, std::hash<unsigned char>, std::equal_to<unsigned char>, std::allocator<std::pair<const unsigned char, long unsigned int> > >]’ 
tests/../histogram.hpp:57:60: instantiated from ‘pnw::histogram<V, C, H>::histogram(const V&, pnw::histogram<V, C, H>::TYPE_t) [with V = std::vector<unsigned char>, C = long unsigned int, H = std::unordered_map<unsigned char, long unsigned int, std::hash<unsigned char>, std::equal_to<unsigned char>, std::allocator<std::pair<const unsigned char, long unsigned int> > >]’ 
tests/t_histogram.cpp:38:61: instantiated from ‘void test_dense_histogram() [with T = unsigned char, C = long unsigned int]’ 
tests/t_histogram.cpp:64:5: instantiated from ‘void test_histograms() [with C = long unsigned int]’ 
tests/t_histogram.cpp:200:29: instantiated from here 
/usr/include/c++/4.6/bits/stl_pair.h:156:2: error: assignment of read-only member ‘std::pair<const unsigned char, long unsigned int>::first’ 
make: *** [tests/t_histogram.o] Error 1 

no es aplicable a std::remove_ifstd::unordered_map?

+0

que cayeron en esta trampa también, pero ahora pensar en ello std :: remove (que se mueve elementos al final del contenedor) no podía trabajar con un contenedor de asociatividad. "el final del contenedor" ya no tiene sentido. – RichardBruce

Respuesta

29

La respuesta es no (no se puede utilizar remove_if en contenedores asociativos). Necesitas hacer un bucle simple; el miembro erase(iterator) ahora devuelve el siguiente iterador válida - por lo que el bucle se convierte en:

for(auto it = begin(m_map); it != end(m_map);) 
{ 
    if (it->second == 0) 
    { 
    it = m_map.erase(it); // previously this was something like m_map.erase(it++); 
    } 
    else 
    ++it; 
} 
+0

Gracias. Ahora sé. Por cierto que estoy realmente anhelo de conceptos C++ ... –

+0

¿Por qué esto tiene tantos votos positivos? ¿Esto no ocurre con 1 elemento? – cjhanks

+0

@cjhanks, ¿me puede mostrar un ejemplo en el que segfaults, lo arreglaré .. – Nim

1

Hay a proposal of Uniform Container Erasure de Stephan T. Lavavej:

template <class K, class T, class H, class P, class A, class Predicate> 
void erase_if(unordered_map<K, T, H, P, A>& c, Predicate pred); 

es decir

std::erase_if(m_map, [](const Bin& bin) { return bin.second == 0; }); 

Por desgracia, no me paré' t lo hace C++ 17. Supongo que esto está relacionado con la adopción del TS Ranges.

Cuestiones relacionadas