2013-03-30 73 views
4

我有这样的代码:unordered_set ::的remove_if():C3892:不能分配给一个变量是常量

unordered_set<AttrValue> output; 
... 

auto requiredType = variables.at(arg.value); 
auto end = remove_if(output.begin(), output.end(), 
    [&](AttrValue x) { 
     return !matchingOutputType(requiredType, ast->getNodeType(ast->getNodeKeyAttribute(x))); 
    }); // queryevaluator_getcandidatelist.cpp(179) 
output.erase(end); 

错误是对代码的4行。所以我认为它是因为remove_if。但最新错误?输出没有定义常量?


Error 90 error C3892: '_Next' : you cannot assign to a variable that is const c:\program files (x86)\microsoft visual studio 10.0\vc\include\algorithm 1840 
Error 109 error C3892: '_Next' : you cannot assign to a variable that is const c:\program files (x86)\microsoft visual studio 10.0\vc\include\algorithm 1840 

输出窗口:

3>c:\program files (x86)\microsoft visual studio 10.0\vc\include\algorithm(1840): error C3892: '_Next' : you cannot assign to a variable that is const 
3>   c:\program files (x86)\microsoft visual studio 10.0\vc\include\algorithm(1853) : see reference to function template instantiation '_FwdIt std::_Remove_if<std::_List_unchecked_const_iterator<_Mylist>,_Pr>(_FwdIt,_FwdIt,_Pr)' being compiled 
3>   with 
3>   [ 
3>    _FwdIt=std::_List_unchecked_const_iterator<std::_List_val<int,std::allocator<AttrValue>>>, 
3>    _Mylist=std::_List_val<int,std::allocator<AttrValue>>, 
3>    _Pr=`anonymous-namespace'::<lambda4> 
3>   ] 
3>   h:\dropbox\sch\cs3202\code\source\query\query evaluator\queryevaluator_getcandidatelist.cpp(179) : see reference to function template instantiation '_FwdIt std::remove_if<std::_List_const_iterator<_Mylist>,`anonymous-namespace'::<lambda4>>(_FwdIt,_FwdIt,_Pr)' being compiled 
3>   with 
3>   [ 
3>    _FwdIt=std::_List_const_iterator<std::_List_val<int,std::allocator<AttrValue>>>, 
3>    _Mylist=std::_List_val<int,std::allocator<AttrValue>>, 
3>    _Pr=`anonymous-namespace'::<lambda4> 
3>   ] 
+0

根据http://www.cprogramming.com/c++11/c++11-auto-decltype-return-value-after-function.html'auto'有时也可以隐含地赋予常量。这是这种情况吗? –

+2

[删除成语与std :: set失败与constness相关的错误]的可能重复(http://stackoverflow.com/questions/3792600/erase-remove-idiom-with-stdset-failing-with-constness-相关的错误) – soon

回答

5

根据标准§23.2.4.6

对于关联容器,其中值类型是一样的 键类型iterator和const_iterator都是常量迭代器。

所以,你甚至不能做

std::unordered_set<int> s{1, 2, 3, 4}; 
*s.begin() = 42; 

,当然,你不能使用std::remove_if(ForwardIt first, ForwardIt last, ...)功能从std::setstd::unordered_set删除元素:

的类型解除引用ForwardIt必须满足MoveAssignable的要求。

+0

那么我该怎么做?我在这里使用set,因为基本上,我只想存储唯一值。如果我使用矢量,我需要检查值是否存在然后插入。直接的方法是将该集合转换为向量,然后从那里开始工作。听起来效率低下?我该如何解决这个问题? –

+2

@JiewMeng,在你的问题的评论中看到[链接](http://stackoverflow.com/questions/3792600/erase-remove-idiom-with-stdset-failing-with-constness-related-error)。 – soon

0

该算法std::remove_if成员函数unordered_set::remove_if,这是在标题中提到,但不存在)并不实际删除任何东西;它通过覆盖与传入标准匹配的元素和序列中后面的元素来重新排序序列。所以它需要一系列可变对象。由unordered_set管理的序列中的对象不可变,因为修改它们可能会破坏容器施加的顺序。

要删除给定键的元素,请使用unordered_set::erase

要删除匹配更广泛的标准,即一种或多种元素,你必须推出自己的:遍历容器寻找匹配(std::find_if将做到这一点),并且他们使用unordered_set::erase发现删除元素。注意:在删除一个元素之后,指向它的迭代器不再有效,所以你的代码必须保存一个指向序列中下一个元素的迭代器。有很多关于如何做到这一点的例子。