在std::remove_if中的const参数

8
我将从一个键值对列表中删除元素。当我使用像 std::pair<const int, bool> 这样的键值对时,会出现以下编译错误:

In file included from /usr/local/include/c++/6.1.0/utility:70:0,

from /usr/local/include/c++/6.1.0/algorithm:60,

from main.cpp:1:

/usr/local/include/c++/6.1.0/bits/stl_pair.h: In instantiation of 'std::pair<_T1, _T2>& std::pair<_T1, _T2>::operator=(std::pair<_T1, _T2>&&) [with _T1 = const int; _T2 = bool]':

/usr/local/include/c++/6.1.0/bits/stl_algo.h:868:16: required from '_ForwardIterator std::__remove_if(_ForwardIterator, _ForwardIterator, _Predicate) [with _ForwardIterator = std::_List_iterator > _Predicate = __gnu_cxx::__ops::_Iter_pred&)> >]'

/usr/local/include/c++/6.1.0/bits/stl_algo.h:936:30: required from '_FIter std::remove_if(_FIter, _FIter, _Predicate) [with _FIter = std::_List_iterator > _Predicate = main()::&)>]'

main.cpp:17:32: required from here

/usr/local/include/c++/6.1.0/bits/stl_pair.h:319:8: error: assignment of read-only member 'std::pair::first'

first = std::forward(__p.first);

以下是示例代码:
int main()
{
    int id = 2;

    std::list< std::pair <const int, bool> >  l;
    l.push_back(std::make_pair(3,true));
    l.push_back(std::make_pair(2,false));
    l.push_back(std::make_pair(1,true));

    l.erase(std::remove_if(l.begin(), l.end(), 
        [id](std::pair<const int, bool>& e) -> bool {
        return e.first == id; }));

    for (auto i: l) {
        std::cout << i.first << " " << i.second << std::endl;
    }
}

我知道(如果我错了请纠正):

  1. I will have exactly the same problem as long as there is constness in any element of the list, for example, a list <const int> will also return a compilation error.

  2. If I remove the const in the first element of the pair the code will work.

  3. The more elegant and efficient way to do it is by using the remove_if list method, like this:

    l.remove_if([id](std::pair<const int, bool>& e) -> bool {
        return e.first == id; });
    

但我的问题是,std::remove_if的内部工作方式究竟是什么,它对容器元素不是const的施加了哪些限制?


std::remove_if要求解引用类型为MoveAssignable,而std::pair<const int, bool>则不满足此条件。 - user657267
2个回答

5

通常情况下,std::remove_if 函数会将逻辑上被删除的值放到序列的末尾,以此来重新排列项目值(通常与成员函数 erase 结合使用,以实际删除逻辑上被删除的值)。当项目无法复制或移动时,它无法进行这种重排。可以改用 std::list::remove_if


4

如果你查看std::remove_if的类型和迭代器要求,你会发现实现必须类似于上面链接中的以下内容:

template<class ForwardIt, class UnaryPredicate>
ForwardIt remove_if(ForwardIt first, ForwardIt last, UnaryPredicate p)
{
    first = std::find_if(first, last, p);
    if (first != last)
        for(ForwardIt i = first; ++i != last; )
            if (!p(*i))
                *first++ = std::move(*i);
    return first;
}

也就是说,该算法只假定迭代器具有前置能力,并且元素可移动,它会对元素进行move操作。当然,不能对const对象进行move操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接