std::remove_if 中的 const 参数

Posted

技术标签:

【中文标题】std::remove_if 中的 const 参数【英文标题】:const arguments in std::remove_if 【发布时间】:2016-12-19 12:04:09 【问题描述】:

我将从对列表中删除元素。当我使用像

这样的一对时

std::pair<const int, bool>

我得到以下编译错误:

在 /usr/local/include/c++/6.1.0/utility:70:0 包含的文件中,

来自/usr/local/include/c++/6.1.0/algorithm:60,

来自 main.cpp:1:

/usr/local/include/c++/6.1.0/bits/stl_pair.h:在实例化 '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:需要来自 '_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:需要来自 '_FIter std::remove_if(_FIter, _FIter, _Predicate) [with _FIter = std::_List_iterator > _Predicate = main()::&)>]'

main.cpp:17:32:从这里需要

/usr/local/include/c++/6.1.0/bits/stl_pair.h:319:8:错误:赋值 只读成员 '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;
    

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

    只要列表的任何元素中存在 constness,我都会遇到完全相同的问题,例如,list &lt;const int&gt; 也会返回编译错误。

    如果我删除该对的第一个元素中的 const,代码将起作用。

    更优雅、更高效的方法是使用 remove_if 列表方法,如下所示:

    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 &lt;const int, bool&gt; 不是。 【参考方案1】:

一般的std::remove_if 将项目值打乱以将逻辑擦除的值放在序列的末尾(它通常与成员函数erase 结合使用以实际删除逻辑擦除的值)。当一个项目不可复制或不可移动时,它不能进行这种洗牌。而是使用std::list::remove_if

【讨论】:

【参考方案2】:

如果你查看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;

即,该算法仅假设迭代器具有前向功能,并且元素是可移动的,并且它 moves 周围的元素。当然,moves 不能对 const 对象执行。

【讨论】:

以上是关于std::remove_if 中的 const 参数的主要内容,如果未能解决你的问题,请参考以下文章

remove_if 中的否定谓词

有没有更好的替代 std::remove_if 从向量中删除元素的方法?

为什么我擦除其他字符时最后一个字符加倍,并且如何防止呢?

char *与const char **函数参数传参问题

如何使用 lambda 擦除空向量单元格?

C++,const型指针变量做形参实参变量的问题