2012-02-06 10 views
7

ho un frammento di codice come questo, deve essere compilato sotto VC++ 2010.set STL incrocio e l'uscita

 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()); 

Per quanto posso dire, questo dovrebbe funzionare. Tuttavia, ottengo errori di generazione:

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>   ] 

Per il gusto di farlo, ho fatto esplicita dichiarazione di parametro di modello:

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() 
); 

Ma io ho gli stessi errori. Il mio problema qui è che nel secondo caso, se passassi un const_iterator, dovrebbe fallire con un errore di conversione tra const_iterator e iterator poiché il tipo di parametro non corrisponderebbe. Cosa mi manca qui? (So ​​che sulla forma "di inserimento" di set_intersection ma voglio imparare cosa faccio di sbagliato qui)

risposta

8

L'argomento output in un std::set_intersection deve essere quello di un mutabile value_type. Gli iteratori di std::set non supportano mai la mutazione, poiché la modifica del valore di un elemento potrebbe cambiare a cui apparteneva nel set . Le funzioni nel gruppo con std::set_iterator sono progettate per per lavorare su sequenze ordinate, ad es. std::vector.

Nel tuo caso, è possibile sostituire la std::set con std::vector, l'ordinamento in base alle necessità (e possibilmente utilizzando l'inserimento std::lower_bound e per tenerli ordinati in fronte di inserimento), o utilizzare std::insert_iterator(res_set, res_set.end()).

+0

Per la cronaca, ho pensato che l'intersezione di due set deve avere una forma banale. Sono un po 'sorpreso che non ci sia un metodo di intersezione che si occupi di set di default. O mi sono perso qualcosa, o quello è un difetto dell'STL. – progician

+0

James, le funzioni impostate sono progettate per essere utilizzate sui set tanto quanto devono essere utilizzate sui vettori ordinati. Cambiare semplicemente l'insieme in un vettore non risolverà nulla. Ciò che è sbagliato è solo il parametro finale, a cui non è possibile scrivere. Un iteratore dell'inserto corregge quello per un set * o * un vettore. –

+0

'std :: set' non è davvero un set in senso matematico. O almeno, è solo parzialmente uno. In generale, in informatica, un set è semplice una collezione non ordinata senza duplicati e una ricerca più o meno rapida. 'std :: set' aggiunge l'ordine, ma soddisfa comunque questa definizione. (Pascal aveva degli insiemi in senso matematico, ma erano limitati a piccoli interi.Più come 'std :: bitset'.) –

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

L'ultimo parametro deve essere un iteratore di uscita. Nel tuo caso, non lo è, ancora di più, è immutabile (bc. std::set ha elementi immutabili). È necessario utilizzare un insert_iterator invece:

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

res_set.begin() non possono essere utilizzati come parametro di output di set_intersection per due motivi:

  • L'insieme è vuoto, e questo avrebbe cercato di sovrascrivere elementi esistenti il set
  • Non è possibile modificare gli elementi di un set.

Invece, si vuole un insert_iterator, per inserire i nuovi elementi nel set:

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