STL установить пересечение и выход - PullRequest
7 голосов
/ 06 февраля 2012

У меня есть такой фрагмент кода, который будет скомпилирован в VC ++ 2010.

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

Насколько я могу судить, это должно сработать. Тем не менее, я получаю ошибки сборки:

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

Ради этого я сделал явное объявление параметра шаблона:

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

Но у меня такие же ошибки. Моя проблема здесь заключается в том, что во втором случае, если я передам const_iterator, он должен завершиться ошибкой преобразования между const_iterator и итератором, поскольку тип параметра не будет совпадать. Что мне здесь не хватает? (Я знаю о форме «вставки» set_intersection, но я хочу узнать, что я здесь делаю неправильно)

Ответы [ 3 ]

11 голосов
/ 06 февраля 2012
    std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(), res_set.begin());

Последний параметр должен быть выходным итератором. В вашем случае это не так, даже более того, он неизменен (bc. std::set имеет неизменные элементы). Вместо этого вы должны использовать insert_iterator:

    std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(), std::inserter(res_set, res_set.end()));
8 голосов
/ 06 февраля 2012

Выходной аргумент для std::set_intersection должен быть изменяемым value_type.Итераторы std::set никогда не поддерживают мутацию, поскольку изменение значения элемента может изменить место его расположения в наборе.Функции в группе с std::set_iterator предназначены для работы с отсортированными последовательностями, например, std::vector.

В вашем случае вы можете либо заменить std::set на std::vector, отсортировав их по мере необходимости (и, возможно, используя std::lower_bound и вставку, чтобы сохранить их сортировку перед вставкой), либо использовать std::insert_iterator( res_set, res_set.end() ).

8 голосов
/ 06 февраля 2012

res_set.begin() нельзя использовать в качестве выходного аргумента set_intersection по двум причинам:

  • Набор пуст, и это попытается перезаписать существующие элементы набора
  • Вы не можете изменять элементы набора.

Вместо этого вы хотите insert_iterator, чтобы вставить новые элементы в набор:

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