使用 remove_if 作为地图容器
using remove_if for a map container
我试图将 remove_if 模板用于地图容器,但我收到模板参数的编译器错误。我无法理解为什么。
int main()
{
map<const int, int> intmap;
intmap[1] = 1;
intmap[2] = 2;
intmap[3] = 3;
intmap[4] = 4;
auto isOdd = [&](pair<const int, int> it)->bool
{ return static_cast<bool>(it.second % 2); };
isOdd(*(intmap.begin()));
remove_if(intmap.begin(), intmap.end(), isOdd);
}
此 remove_if 引发编译器错误。有什么修复建议吗?
错误信息是
C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\INCLUDE\utility(260) : error C2166: l-value specifies const object
C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\INCLUDE\utility(259) : while compiling class template member function
'std::pair<_Ty1,_Ty2> &std::pair<_Ty1,_Ty2>::operator =(std::pair<_Ty1,_Ty2> &&)'
with
[
_Ty1=const int,
_Ty2=int
]
maperaseif.cpp(29) : see reference to class template instantiation 'std::pair<_Ty1,_Ty2>' being compiled
with
[
_Ty1=const int,
_Ty2=int
]
你不能在 map
上使用 remove_if
,因为它的值类型实际上是 std::pair<const Key, Value>
,但是你看 requirements of remove_if,你可以看到,那个取消引用的迭代器类型应该是 MoveAssignable
.
只写循环,或者用boost为例
remove_if
通过扫描元素来工作,一旦要删除一个元素,它会记住将离开的 "gap"(保持迭代器指向那里),同时推进另一个迭代器以找到下一个要保留的元素...然后它开始将元素从后一个位置复制或移动到前一个位置,直到到达 end()
.
这对 map
不起作用,因为您不能完全覆盖 pair<key,value>
元素:不允许修改键值或排序顺序不变的实现需求可能会失效。
因此,您需要放弃 remove_if
。您可以使用普通循环,注意保存迭代器到下一个元素,而不是尝试从刚刚擦除的迭代器前进。关于如何在迭代时从地图中删除元素的许多其他问题,例如here.....
这个 erase_if
模板化函数应该可以满足您的需求。 (不是我写的,只是从某处捡来的 - 所以感谢谁做的!)
template< typename ContainerT, typename PredicateT >
void erase_if( ContainerT& items, const PredicateT& predicate ) {
for( auto it = items.begin(); it != items.end(); ) {
if( predicate(*it) ) it = items.erase(it);
else ++it;
}
};
在您的示例中,您可以这样使用它:
erase_if(intmap, isOdd);
我试图将 remove_if 模板用于地图容器,但我收到模板参数的编译器错误。我无法理解为什么。
int main()
{
map<const int, int> intmap;
intmap[1] = 1;
intmap[2] = 2;
intmap[3] = 3;
intmap[4] = 4;
auto isOdd = [&](pair<const int, int> it)->bool
{ return static_cast<bool>(it.second % 2); };
isOdd(*(intmap.begin()));
remove_if(intmap.begin(), intmap.end(), isOdd);
}
此 remove_if 引发编译器错误。有什么修复建议吗?
错误信息是
C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\INCLUDE\utility(260) : error C2166: l-value specifies const object
C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\INCLUDE\utility(259) : while compiling class template member function
'std::pair<_Ty1,_Ty2> &std::pair<_Ty1,_Ty2>::operator =(std::pair<_Ty1,_Ty2> &&)'
with
[
_Ty1=const int,
_Ty2=int
]
maperaseif.cpp(29) : see reference to class template instantiation 'std::pair<_Ty1,_Ty2>' being compiled
with
[
_Ty1=const int,
_Ty2=int
]
你不能在 map
上使用 remove_if
,因为它的值类型实际上是 std::pair<const Key, Value>
,但是你看 requirements of remove_if,你可以看到,那个取消引用的迭代器类型应该是 MoveAssignable
.
只写循环,或者用boost为例
remove_if
通过扫描元素来工作,一旦要删除一个元素,它会记住将离开的 "gap"(保持迭代器指向那里),同时推进另一个迭代器以找到下一个要保留的元素...然后它开始将元素从后一个位置复制或移动到前一个位置,直到到达 end()
.
这对 map
不起作用,因为您不能完全覆盖 pair<key,value>
元素:不允许修改键值或排序顺序不变的实现需求可能会失效。
因此,您需要放弃 remove_if
。您可以使用普通循环,注意保存迭代器到下一个元素,而不是尝试从刚刚擦除的迭代器前进。关于如何在迭代时从地图中删除元素的许多其他问题,例如here.....
这个 erase_if
模板化函数应该可以满足您的需求。 (不是我写的,只是从某处捡来的 - 所以感谢谁做的!)
template< typename ContainerT, typename PredicateT >
void erase_if( ContainerT& items, const PredicateT& predicate ) {
for( auto it = items.begin(); it != items.end(); ) {
if( predicate(*it) ) it = items.erase(it);
else ++it;
}
};
在您的示例中,您可以这样使用它:
erase_if(intmap, isOdd);