尝试在矢量上使用擦除功能时“没有匹配的调用功能”

Posted

技术标签:

【中文标题】尝试在矢量上使用擦除功能时“没有匹配的调用功能”【英文标题】:"no matching function for call" when trying to use the erase function on a vector 【发布时间】:2019-08-05 14:43:42 【问题描述】:

我正在尝试使用擦除功能从我的向量中删除任何值为 0 的整数。

void eliminateZeroes(std::vector<int> &answers)
    auto i = answers.cbegin();
    while(i != answers.cend())
        if(*i == 0)
            i = answers.erase(i);
        else
            i++;
        

    

我希望该函数从向量中删除任何值为 0 的项目。

错误信息:

/home/ec2-user/environment/DP378-Havel_Hakimi_-_Easy/main.cpp: In function ‘void eliminateZeroes(std::vector<int>&)’:
/home/ec2-user/environment/DP378-Havel_Hakimi_-_Easy/main.cpp:32:36: error: no matching function for call to ‘std::vector<int>::erase(__gnu_cxx::__normal_iterator<const int*, std::vector<int> >&)’
                 i = answers.erase(i);
                                    ^
/home/ec2-user/environment/DP378-Havel_Hakimi_-_Easy/main.cpp:32:36: note: candidates are:
In file included from /usr/include/c++/4.8.5/vector:69:0,
                 from /home/ec2-user/environment/DP378-Havel_Hakimi_-_Easy/main.cpp:1:
/usr/include/c++/4.8.5/bits/vector.tcc:134:5: note: std::vector<_Tp, _Alloc>::iterator std::vector<_Tp, _Alloc>::erase(std::vector<_Tp, _Alloc>::iterator) [with _Tp = int; _Alloc = std::allocator<int>; std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::__normal_iterator<int*, std::vector<int> >; typename std::_Vector_base<_Tp, _Alloc>::pointer = int*]
     vector<_Tp, _Alloc>::
     ^
/usr/include/c++/4.8.5/bits/vector.tcc:134:5: note:   no known conversion for argument 1 from ‘__gnu_cxx::__normal_iterator<const int*, std::vector<int> >’ to ‘std::vector<int>::iterator aka __gnu_cxx::__normal_iterator<int*, std::vector<int> >’
/usr/include/c++/4.8.5/bits/vector.tcc:146:5: note: std::vector<_Tp, _Alloc>::iterator std::vector<_Tp, _Alloc>::erase(std::vector<_Tp, _Alloc>::iterator, std::vector<_Tp, _Alloc>::iterator) [with _Tp = int; _Alloc = std::allocator<int>; std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::__normal_iterator<int*, std::vector<int> >; typename std::_Vector_base<_Tp, _Alloc>::pointer = int*]
     vector<_Tp, _Alloc>::
     ^
/usr/include/c++/4.8.5/bits/vector.tcc:146:5: note:   candidate expects 2 arguments, 1 provided

【问题讨论】:

我记得 libstdc++ 已经开始支持 C++11 但一些容器缺少新的 erase(const_iterator) 重载。但我不认为std::vector 有这个问题。 @TomJB 看来您使用的是旧编译器。写 auto i = answers.begin();而不是 auto i = answers.cbegin(); @VladfromMoscow 就是这样!!非常感谢。作为一个额外的好处,我的函数在它第一次编译时就可以工作......很高兴改变! 顺便说一句,@TomJB:不要编写自己的循环,而是查看 C++ 的 std::remove 算法和 erase-remove idiom。这样效率更高,因为每个元素最多只需要移动一次。 @TomJB 另见我的回答。 【参考方案1】:

您似乎使用的是不完全支持 C++ 11 标准的旧编译器。

问题是函数cbegin产生的常量迭代器

auto i = answers.cbegin();

不能转换为在 C++ 11 标准之前的成员函数 erase 的旧声明中使用的非常量迭代器。

在当前的 C++ 标准中,函数声明如下

iterator erase(const_iterator position);

你的代码应该可以编译了。

所以不是

auto i = answers.cbegin();

你需要使用

auto i = answers.begin();

但无论如何,最好按照以下方式定义函数

#include <vector>
#include <algorithm>

std::vector<int> & eliminateZeroes( std::vector<int> &answers )

    answers.erase( std::remove( answers.begin(), answers.end(), 0 ), answers.end() );

    return answers;

如果您的编译器支持在标头&lt;iterator&gt; 中声明的通用函数beginend 等,那么该函数也可以像这样重写

#include <vector>
#include <algorithm>
#include <iterator>

std::vector<int> & eliminateZeroes( std::vector<int> &answers )

    answers.erase( std::remove( std::begin( answers ), std::end( answers ), 0 ), std::end( answers ) );

    return answers;

【讨论】:

std::beginstd::end 不需要限定,它们会被 ADL 找到。 @BenVoigt 我认为这种方法是一种糟糕的编程风格。:) 然后using std::begin; 在本地范围内,以便将来的读者理解它会被发现。但是禁用 ADL 比依赖它更糟糕。 我可以问这个问题吗? std::remove 函数显然返回:“一个迭代器,指向未删除的最后一个元素之后的元素。”。它将这个返回到擦除函数,该函数擦除迭代器指向的位置处的项目。对我来说,这似乎是告诉擦除功能删除我们不想要的东西?它工作得很好,所以我一定是误解了。 @TomJB 演示程序中使用的擦除函数使用了两个迭代器。第一个指向被 std::remove 删除的第一个元素,第二个迭代器指向序列的末尾。那就是序列的尾部包含我们要删除的元素。

以上是关于尝试在矢量上使用擦除功能时“没有匹配的调用功能”的主要内容,如果未能解决你的问题,请参考以下文章

矢量擦除迭代器超出范围[关闭]

尝试擦除最后一个std :: vector元素时程序崩溃

c_cpp 使用矢量擦除实现队列

“向量擦除迭代器超出范围”错误

矢量排序和擦除不起作用

为啥在Visual Studio中擦除位置之前矢量的c ++迭代器也无效?