Question

i ran across something similar to the below code snippet, which throws a compiler error because its using a const_iterator. is there a reason why vec.end() in std::copy does not implicitly get a const cast ?

int main(int argc, char* argv[]) {

    vector<int> vec;
    vec.push_back(20);
    vec.push_back(30);
    vector<int> copy_vec;
    vector<int>::const_iterator i = vec.begin();
    std::copy(i,vec.end(),back_inserter(copy_vec));
    cerr<<copy_vec.size()<<endl;
    return 0;
}
Was it helpful?

Solution

No need of std::copy, neither you need a pair of iterators.

Just do this:

vector<int> copy_vec(vec); //use the copy constructor!

And you're done!

As for your code why it is giving error, is because the first iterator to std::copy is a const_iterator, but the second iterator is just iterator. Both has to be same type, but they are not, and because of that the template argument deduction fails for std::copy which is a function template.

To understand this with an example, consider this simple code:

template<typename T>
void f(T a, T b) {}

int main()
{
    int a = 100;
    char b = 'A';
    f(a,b);
}

It is giving error (see ideone):

prog.cpp:8: error: no matching function for call to ‘f(int&, char&)’

It doesn't compile because we're relying on template argument deduction. Since the type of the first parameter and second parameter is exactly same in the function template but we call this function passing a (which is int) as first argument and b (which is char) as second argument, it cannot deduce T uniquely from arguments of different types! Please note that conversion is not considered during template argument deduction.

However, if we do not rely on template argument deduction, and instead provide the template argument explicitly, then it would work (see ideone):

f<int>(a,b);  //works!

It works as there is no need to deduce T from function arguments!

Similarly, if you provide the template argument for std::copy, then even your code would work (see ideone):

std::copy<vector<int>::const_iterator>(i,vec.end(),back_inserter(copy_vec));
       //^^^^^^^^^^^^^^^^^^^^^^^^^^^^ explicitly provide template argument!

It works because iterator can convert into const_iterator, but const_iterator cannot convert into iterator which means the following would give error (see ideone):

std::copy<vector<int>::iterator>(i,vec.end(),back_inserter(copy_vec));
        //^^^^^^^^^^^^^^^^^^^^^ non-const iterator!

OTHER TIPS

vec is a non-const vector, and so end will return a non-const iterator. Such an iterator actually cannot be implicitly converted to a const version, because they're separate classes.

Instead, use the two iterator constructor:

vector<int> copy_vec(vec.begin(), vec.end());

I think that the problem here is that std::copy is declared to take three parameters.

The first two are of the same type, and you are passing ( const_iterator, vec.end () ) - and vec.end() is returning a non-const iterator (because vec is a non-const vector). This causes the compiler to reject the template for std::copy.

If you had a function like this:

void doit ( const std::vector<int> &vec, std::vector<int> &out ) {
    std::vector<int>::const_iterator i = vec.begin();
    std::copy(i,vec.end(),back_inserter(out));
    }

Then it will compile and work fine, because vec.end () will return a const_iterator. Alternately, if you are using C++11, you can call vec.cend () to get a const_iterator.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top