简体   繁体   中英

Converting vector<>::const_iterator to vector<>::iterator

I am coding my very own vector container. To do so, I have a vector class and a RAIterator (Random Access Iterator) class. In my vector class I am implementing all of std::vector member functions. Amongst them is begin() which returns an iterator to the first element of the vector. There is also an overload which returns a constant iterator. My functions look like this:

iterator        begin() { return (iterator(_data)); }
const_iterator  begin() const { return (const_iterator(_data)); }

Here iterator and const_iterator are the same as in iterator_traits. My main looks like this:

int main(void)
{
    ft::vector<int> v;

    ft::vector<int>::iterator it2 = v.begin();
    ft::vector<int>::const_iterator it = v.begin();
}

ft is the namespace I am using to create my vector. The first call to v.begin() is alright but the second is not. This is because the first begin() function is called both times and since it returns iterator , the compiler tells me that there is no available conversion from iterator to const_iterator . Here is the actual error I receive:

main.cpp:70:34: error: no viable conversion from 'RAIterator<ft::vector<int, std::__1::allocator<int> >::pointer>' to
      'RAIterator<ft::vector<int, std::__1::allocator<int> >::const_pointer>'
        ft::vector<int>::const_iterator it = v.begin();
                                        ^    ~~~~~~~~~
./iterators/RAIterator.hpp:49:9: note: candidate constructor not viable: no known conversion from 'ft::vector<int,
      std::__1::allocator<int> >::iterator' (aka 'RAIterator<int *>') to 'const int *' for 1st argument
        RAIterator(T src) : _ptr(src) { /*std::cout << "Second constructor called" << std::endl;*/ }
        ^
./iterators/RAIterator.hpp:50:9: note: candidate constructor not viable: no known conversion from 'ft::vector<int,
      std::__1::allocator<int> >::iterator' (aka 'RAIterator<int *>') to 'const ft::RAIterator<const int *> &' for 1st argument
        RAIterator(const RAIterator &src) : _ptr(src._ptr) { /*std::cout << "Third constructor called" << std::endl;*/ } // CHANGE
        ^
1 error generated.

Here are my RAIterator class constructors:

RAIterator() : _ptr(NULL) { /*std::cout << "First constructor called" << std::endl;*/ }
RAIterator(T src) : _ptr(src) { /*std::cout << "Second constructor called" << std::endl;*/ }
RAIterator(const RAIterator &src) : _ptr(src._ptr) { /*std::cout << "Third constructor called" << std::endl;*/ } // CHANGE

I don't know how to solve this problem, ie how to make this conversion possible. If I write std instead of ft it compiles correctly, so I have to be able to support this conversion.

PS I have to use C++98. Weird, right?

You can add a converting constructor.

In C++98 there aren't all the helpful traits to only allow the template constructor when T is pointer to const, and U is the corresponding pointer to mutable, so it will always participate in overload resolution, but instantiating it will fail for incompatible pointer types.

template<typename T>
class RAIterator {
    T _ptr;
public:
    RAIterator() : _ptr(nullptr) {}
    RAIterator(T src) : _ptr(src) {}
    RAIterator(const RAIterator &src) : _ptr(src._ptr) {}
    template<typename U>
    // requires std::same_as<std::remove_pointer_t<T>, const std::remove_pointer_t<U>>
    RAIterator(const RAIterator<U> &src) : _ptr(src._ptr) {}

    // all your existing stuff
};

C++ does not support function overloading based on return types, only on argument types (where this is also considered an argument). So there is no way for the compiler to distinguish the two v.begin() calls.

If you call begin() on a const object, you'll see that it calls the const overload:

    ft::vector<int> const &const_v = v;
    ft::vector<int>::const_iterator it = const_v.begin();

But that is a bit silly, of course.

In C++11, cbegin and cend were added to make this easier.

But why does it work unmodified in std::vector ? I can't find any documentation on this, but I think the reason must be that std::vector::iterator supports implicit conversion to std::vector::const_iterator .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM