2012-02-06 24 views
7

que tienen un fragmento de código como este, para ser compilado bajo VC++ 2010.conjunto STL intersección y la salida

 std::set<int> s1; 
     std::set<int> s2; 
     std::set<int> res_set; 
     std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(), res_set.begin()); 

Por lo que yo puedo decir, esto supone que funciona. Sin embargo, consigo errores de compilación:

c:\program files (x86)\microsoft visual studio 10.0\vc\include\algorithm(4494): error C3892: 'std::_Tree_const_iterator<_Mytree>::operator *' : you cannot assign to a variable that is const 
1>   with 
1>   [ 
1>    _Mytree=std::_Tree_val<std::_Tset_traits<int,std::less<int>,std::allocator<int>,false>> 
1>   ] 
1>   c:\program files (x86)\microsoft visual studio 10.0\vc\include\algorithm(4522) : see reference to function template instantiation '_OutIt std::_Set_intersection<_InIt1,_InIt2,_OutIt>(_InIt1,_InIt1,_InIt2,_InIt2,_OutIt)' being compiled 
1>   with 
1>   [ 
1>    _OutIt=std::_Tree_const_iterator<std::_Tree_val<std::_Tset_traits<int,std::less<int>,std::allocator<int>,false>>>, 
1>    _InIt1=std::_Tree_unchecked_const_iterator<std::_Tree_val<std::_Tset_traits<int,std::less<int>,std::allocator<int>,false>>>, 
1>    _InIt2=std::_Tree_unchecked_const_iterator<std::_Tree_val<std::_Tset_traits<int,std::less<int>,std::allocator<int>,false>>> 
1>   ] 
1>   c:\program files (x86)\microsoft visual studio 10.0\vc\include\algorithm(4549) : see reference to function template instantiation '_OutIt std::_Set_intersection1<std::_Tree_unchecked_const_iterator<_Mytree>,std::_Tree_unchecked_const_iterator<_Mytree>,_OutIt>(_InIt1,_InIt1,_InIt2,_InIt2,_OutIt,std::tr1::true_type)' being compiled 
1>   with 
1>   [ 
1>    _OutIt=std::_Tree_const_iterator<std::_Tree_val<std::_Tset_traits<int,std::less<int>,std::allocator<int>,false>>>, 
1>    _Mytree=std::_Tree_val<std::_Tset_traits<int,std::less<int>,std::allocator<int>,false>>, 
1>    _InIt1=std::_Tree_unchecked_const_iterator<std::_Tree_val<std::_Tset_traits<int,std::less<int>,std::allocator<int>,false>>>, 
1>    _InIt2=std::_Tree_unchecked_const_iterator<std::_Tree_val<std::_Tset_traits<int,std::less<int>,std::allocator<int>,false>>> 
1>   ] 
1>   c:\p4r\pkrcode\depot\dev\stats\poker\protype\statserver\achievementmanager.cpp(175) : see reference to function template instantiation '_OutIt std::set_intersection<std::_Tree_const_iterator<_Mytree>,std::_Tree_const_iterator<_Mytree>,std::_Tree_const_iterator<_Mytree>>(_InIt1,_InIt1,_InIt2,_InIt2,_OutIt)' being compiled 
1>   with 
1>   [ 
1>    _OutIt=std::_Tree_const_iterator<std::_Tree_val<std::_Tset_traits<int,std::less<int>,std::allocator<int>,false>>>, 
1>    _Mytree=std::_Tree_val<std::_Tset_traits<int,std::less<int>,std::allocator<int>,false>>, 
1>    _InIt1=std::_Tree_const_iterator<std::_Tree_val<std::_Tset_traits<int,std::less<int>,std::allocator<int>,false>>>, 
1>    _InIt2=std::_Tree_const_iterator<std::_Tree_val<std::_Tset_traits<int,std::less<int>,std::allocator<int>,false>>> 
1>   ] 

Por el bien de ella, me hace explícita declaración de parámetros de plantilla:

std::set_intersection<std::set<int>::const_iterator, std::set<int>::const_iterator, std::set<int>::iterator>(
    s1.begin(), s1.end(), s2.begin(), s2.end(), res_set.begin() 
); 

Pero tengo los mismos errores. Mi problema aquí es que en el segundo caso, si pasara un const_iterator, debería fallar con un error de conversión entre const_iterator e iterator ya que el tipo de parámetro no coincidiría. ¿Qué me falta aquí? (Que sé de la forma "de inserción" de set_intersection pero quiero aprender lo que hago mal aquí)

Respuesta

8

El argumento de salida a un std::set_intersection debe ser a un mutable value_type. Los iteradores de std::set nunca admiten la mutación, ya que el cambio del valor de un elemento podría cambiar donde pertenecía a el conjunto. Las funciones en el grupo con std::set_iterator están diseñadas para trabajar en secuencias ordenadas, p. std::vector.

En su caso, puede reemplazar su std::set con std::vector, ordenándolos según sea necesario (y posiblemente usando std::lower_bound y inserción para mantenerlos ordenados en la cara de inserción), o utilizar std::insert_iterator(res_set, res_set.end()).

+0

Para el registro, pensé que la intersección de dos conjuntos debe tener una forma trivial. Estoy un poco sorprendido de que no haya un método de intersección que trate con los conjuntos por defecto. O me perdí algo, o esa es una deficiencia del STL. – progician

+0

James, las funciones de conjunto están diseñadas para ser utilizadas en juegos tanto como para ser utilizadas en vectores ordenados. Simplemente cambiar el conjunto a un vector no resolverá nada. Lo que está mal es solo el parámetro final, que no se puede escribir. Un iterador de inserción corrige eso para un conjunto * o * un vector. –

+0

'std :: set' no es realmente un conjunto en el sentido matemático. O al menos, es solo parcialmente uno. En general, en ciencias de la computación, un conjunto es simple una colección desordenada sin duplicados y una búsqueda más o menos rápida. 'std :: set' agrega orden, pero de lo contrario cumple con esta definición. (Pascal tenía conjuntos en el sentido matemático, pero estaban limitados a enteros pequeños).Más como 'std :: bitset'.) –

11
std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(), res_set.begin()); 

El último parámetro debe ser un iterador de salida. En su caso, no es, aún más, es inmutable (bc. std::set tiene elementos inmutables). Debe utilizar un insert_iterator lugar:

std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(), std::inserter(res_set, res_set.end())); 
8

res_set.begin() no puede ser utilizado como el argumento de salida de set_intersection por dos razones:

  • El conjunto está vacío, y esto sería tratar de sobrescribir los elementos existentes de el conjunto
  • No puede modificar elementos de un conjunto.

su lugar, desea una insert_iterator, para insertar los nuevos elementos en el conjunto:

std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(), 
         std::inserter(res_set, res_set.end()))