std :: set :: iterator转换错误

时间:2012-03-20 17:24:55

标签: c++ visual-studio-2010 set

我正在使用std::set来保存Board类型的成员,并且我希望迭代该集以进行无法与find方法一起使用的比较,因为将使用不同的条件进行排序经文定位。

1>c:\...\project.cpp(1140): error C2440: 'initializing' : cannot convert from 'std::_Tree_const_iterator<_Mytree>' to 'std::_Tree_const_iterator<_Mytree>'
1>          with
1>          [
1>              _Mytree=std::_Tree_val<std::_Tset_traits<Board,std::greater<Board>,std::allocator<Board>,false>>
1>          ]
1>          and
1>          [
1>              _Mytree=std::_Tree_val<std::_Tset_traits<Board,std::less<Board>,std::allocator<Board>,false>>
1>          ]
1>          No constructor could take the source type, or constructor overload resolution was ambiguous

事情是迭代器不应该是const。该方法不是const,该方法是在方法的本地创建的,我并没有将迭代器作为const。

Thing::Thing thisFunction(int action){
    // snip 
    set<Board, less<Board>> openSet;
    // snip 
    for(set<Board>::iterator ii = openSet.begin();  // line 1140
        ii != openSet.end(); ii++){
            // snip 
    }

这没有直接意义,因为迭代器没有被声明为const,所以它不应该试图考虑const。

分别为什么当我使用std::_tree时,编译器会讨论std::set

3 个答案:

答案 0 :(得分:4)

我认为你有一个比我在下面描述的更简单的问题......

尝试更改for循环:

for (set<Board>::iterator ii = openSet.begin(); ii != openSet.end(); ii++) { //...

为:

for (set<Board, less<Board> >::iterator ii = openSet.begin(); ii != openSet.end(); ii++) { //...

因此编译器认为不需要进行转换。似乎还有其他事情发生在代码中,因为less<Board>应该是默认的比较器。

如果您发布的错误多于第一行,那么事情会更清楚一些。


set::iterator始终是VS 2010中的const_iterator。

如果要“修改”迭代器引用的元素,则需要从集合中删除该元素,创建新元素(不一定按该顺序)并将新元素插入集合中。

它执行此操作的方式隐藏在_Tree模板类型中std::set派生自_Tree是为std::set提供大部分实现的类型, std::multisetstd::mapstd::multimap - 这就是您在错误中看到_Tree的引用的原因。 _Tree类型如此声明iterator(在<xtree>标题中):

typedef _Tree_const_iterator<_Mybase>
    const_iterator;

typedef typename _STD tr1::conditional<
    _STD tr1::is_same<key_type, value_type>::value,
    const_iterator,
    _Tree_iterator<_Mybase> >::type iterator;

因此,如果键类型与值类型相同(例如对于std:set,则迭代器是_Tree的{​​{1}}的类型定义。< / p>

Scott Meyers在“Effective STL”,“Item 22:避免set和multiset中的就地密钥修改”中讨论了这一点,包括一些编译器将如何使用const_iterator样式的std :: set迭代器。

答案 1 :(得分:3)

问题比较简单,你不能指定一个

std::set<Board, std::greater<Board>>::iterator 

std::set<Board>::iterator 

因为实际上是 a

std::set<Board, std::less<Board>>::iterator 

标准不保证这些类型相同,并且不保证它们之间会有转换。在实践中,这些总是不同的类型,并且没有转换。因此你的错误。

答案 2 :(得分:0)

std::set是一个有序的容器,所以如果你允许迭代集合和muck以及其中项目的内部状态,你可能会导致排序顺序发生变化,从而将集合保留在不一致的状态。为防止出现这种情况,std::set::iterator::operator->会返回const std::set::value_type*而不是std::set::value_type*

因此,以下示例进行编译,但如果将Foo::bar更改为非const成员函数,则编译将失败。

#include <set>

struct Foo 
{
  void bar() const {} // must be const
};

int main()
{
  std::set<Foo> mySet;

  for( std::set<Foo>::iterator it = mySet.begin(); it != mySet.end(); ++it ) {
    it->bar();
  }
}

编辑:
要修复原始错误,您只需在循环中调用const个成员函数。如果确实需要改变集合中项目的状态,则不能在适当的位置进行。正如Michael Burr在他的answer中建议复制一样,删除原件,修改副本并将其重新插入到集合中。