Thomas Dupond
Thomas Dupond

Reputation: 81

Conversion error when returning an Iterator

I'm experimenting with the "find" function. I can't seem to be able to return the iterator.

template<typename T>                                                                                                  
typename T::iterator do_find(const T &v, int f)                                                                       
{                                                                                                                     
    return find(v.begin(), v.end(), f);                                                                           
}

And here is my main :

int main()                                                                                                            
{                                                                                                                     
    std::vector<int> v = {1, 2, 3, 3, 4, 6};                                                                      
    std::vector<int>::iterator it;                                                                                
    it = do_find(v, 3);                                                                                           
    return 0;                                                                                                     
}      

When I compile I get the following error :

error: impossible de convertir
« std::find<__gnu_cxx::__normal_iterator<const int*, std::vector<int> >, int>((& v)->std::vector<int>::begin(), (& v)->std::vector<int>::end(), f) » de « __gnu_cxx::__normal_iterator<const int*, std::vector<int> > » vers « std::vector<int>::iterator {aka __gnu_cxx::__normal_iterator<int*, std::vector<int> >} »

Upvotes: 2

Views: 577

Answers (3)

songyuanyao
songyuanyao

Reputation: 172924

v is declared as const, then for std::vector, both v.begin() and v.end() return std::vector::const_iterator, then the return type of find will be std::vector::const_iterator too; it can't be converted to std::vector::iterator implicitly.

You can change the return type, e.g.

template<typename T>                                                                                                  
typename T::const_iterator do_find(const T &v, int f)                                                                       
{                                                                                                                     
    return find(v.begin(), v.end(), f);                                                                           
}

or just

template<typename T>                                                                                                  
auto do_find(const T &v, int f)                                                                       
{                                                                                                                     
    return find(v.begin(), v.end(), f);                                                                           
}

then

auto it = do_find(v, 3); 

If you want to modify the element through the returned iterator, then you should declare the parameter v to be non-const.

template<typename T>                                                                                                  
auto do_find(T &v, int f)                                                                       
{                                                                                                                     
    return find(v.begin(), v.end(), f);                                                                           
}

Note that with auto, the above do_find will return iterator if you pass a non-const vector, and return const_iterator if you pass a const vector.

Upvotes: 3

Vlad from Moscow
Vlad from Moscow

Reputation: 310980

Within the function the container is declared as a constant container

template <typename T>
typename T::iterator do_find(const T &v, int f);
                             ^^^^^^^^^^  

So the member functions begin and end of this container return objects of the type typename T::const_iterator that can not be implicitly converted to the type.typename T::iterator.

Also it is not clear why the second parameter has the type int instead of the type typename T::value_type.

There is a magic word auto in C++ that can simplify the function declaration and using its return value.

The function can be defined the following way

template <typename T>        
auto do_find( const T &v, typename T::value_type value ){                                                                                                                     
    return std::find( v.begin(), v.end(), value );           
}

Here is a demonstrative program

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

template <typename T>        
auto do_find( const T &v, typename T::value_type value ){                                                                                                                     
    return std::find( v.begin(), v.end(), value );           
}

int main() 
{
    std::vector<int> v = { 1, 2, 3, 3, 4, 6 };

    auto it = do_find(v, 3);  

    if ( it != v.end() )
    {
        std::cout << *it << " is found at position "
                  << std::distance( v.cbegin(), it ) << std::endl;
    }

    return 0;
}

Its output is

3 is found at position 2

Upvotes: 0

UKMonkey
UKMonkey

Reputation: 6983

v is const; meaning that std::find will return a T::const_iterator. You're attempting to return a T::iterator; and the compiler can't convert from const to non-const.

The fix is to either return the const_iterator or to make v non-const. Depending on exactly what you want to do with the iterator.

Upvotes: 1

Related Questions