cannot bind const_iterator to const_iterator

190 Views Asked by At
#include <iostream>
#include <vector>

using namespace std;

void print(vector<int>::const_iterator &beg, vector<int>::const_iterator &end);

int main()
{
    vector<int> ivec = {1, 2, 3, 4, 5};
    print(ivec.cbegin(), ivec.cend());

    return 0;
}

void print(vector<int>::const_iterator &beg, vector<int>::const_iterator &end)
{
    if (beg == end)
    {
        cout << "over" << endl;
        return;
    }
    cout << *beg << endl;
    print(++beg, end);
}

ubuntu 20, g++ 9.0

rec_print_vect.cpp: In function ‘int main()’:
rec_print_vect.cpp:11:19: error: cannot bind non-const lvalue reference of type ‘std::vector<int>::const_iterator&’ {aka ‘__gnu_cxx::__normal_iterator<const int*, std::vector<int> >&’} to an rvalue of type ‘std::vector<int>::const_iterator’ {aka ‘__gnu_cxx::__normal_iterator<const int*, std::vector<int> >’}
   11 |  print(ivec.cbegin(), ivec.cend());
      |        ~~~~~~~~~~~^~
rec_print_vect.cpp:6:41: note:   initializing argument 1 of ‘void print(std::vector<int>::const_iterator&, std::vector<int>::const_iterator&)’
    6 | void print(vector<int>::const_iterator &beg, vector<int>::const_iterator &end);
 

const int &i = 10 is leagl, right? why const_iterator can not? I am puzzled. This program just want to recursive print a vector. I want to use reference for the iterator. Because I donot need to modify elements in vector, I used the const_iterator with cbegin() and cend() memeber function. I think bind a const var reference to a const var or literal value is right. But my code cannot pass compiling stage. If I use const_iterator not const_iterator& in function fomal args, my code could run well.

2

There are 2 best solutions below

0
YSC On

Here you go:

void print(vector<int>::const_iterator beg, vector<int>::const_iterator end);

The thing is, you cannot bind a temporary (the iterators returned by begin() et al.) to a non-const reference. So either accept vector<int>::const_iterator const& or take those iterators by value (which isn't that bad).

1
Vlad from Moscow On

The function parameters

void print(vector<int>::const_iterator &beg, vector<int>::const_iterator &end);

are non-constant references. While the arguments in this call

print(ivec.cbegin(), ivec.cend());

are temporary objects returned by the member functions cbegin and cend. You may not bind a non-constant lvalue reference with a temporary object.

Declare the function like

void print(vector<int>::const_iterator beg, vector<int>::const_iterator end);

Pay attention to that the function can invoke undefined behavior when it is called for an empty vector due to this statement

if (beg + 1 == end)

The function could be defined simpler.

void print(vector<int>::const_iterator beg, vector<int>::const_iterator end)
{ 
    if ( beg != end )
    {
        std::cout << *beg << '\n';
        print( ++beg, end );
    }
}

Or the function can be defined as it is shown in the demonstrative program below.

#include <iostream>
#include <vector>
#include <iterator>

std::ostream & print( std::vector<int>::const_iterator beg, 
                      std::vector<int>::const_iterator end, 
                      std::ostream &os = std::cout )
{
    return beg != end ? os << *beg << '\n', print( ++beg, end ) : os;
}

int main() 
{
    std::vector<int> ivec = {1, 2, 3, 4, 5};
    
    print( std::begin( ivec ), std::end( ivec ) ) << std::endl;
    
    return 0;
}

Its output is

1
2
3
4
5