Search code examples
c++algorithmc++11vectorerase

"no matching function for call" when trying to use the erase function on a vector


I'm trying to use the erase function to delete any ints from my vector with a value of 0.

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

    }

I expect the function to remove any items from the vector which are valued 0.

Error message:

/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

Solution

  • It seems that you are using an old compiler that does not completely support the C++ 11 Standard.

    The problem is that the constant iterator produced by the function cbegin

    auto i = answers.cbegin();
    

    can not be converted to a non-constant iterator that is used in the old declaration of the member function erase prior the C++ 11 Standard.

    In the current C++ Standard the function is declared like

    iterator erase(const_iterator position);
    

    and your code should compile.

    So instead of

    auto i = answers.cbegin();
    

    you need to use

    auto i = answers.begin();
    

    But in any case it is better to define the function the following way

    #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;
    }
    

    If your compiler supports general functions begin, end and so on declared in the header <iterator> then the function can be rewritten also like

    #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;
    }