Reputation: 235
I am trying to implement std::list, for learning process as I just started studying linked and doubly-linked list in school.
Here is the code stripped down to only the part that is causing. Stripped down to make reading better to be able to analyze the problem.
For the full code (that is still a working in progress) here is the link: https://www.onlinegdb.com/edit/rJKzbN9ID
#include <iostream>
using namespace std;
template <typename T>
class List
{
//SFINAE
template <typename Iter>
using required_input_iterator = std::enable_if<std::is_base_of_v<std::input_iterator_tag,
typename std::iterator_traits<Iter>::iterator_category >>;
public:
using reference = T&;
using const_reference = const T&;
using size_type = std::size_t;
class const_iterator ;
class iterator : public std::input_iterator_tag
{
};
class const_iterator
{
};
List() = default;
List(std::initializer_list<T> i_list);
// iterators
const_iterator end() const noexcept {};
iterator end() noexcept {};
const_iterator cend() const {};
template<typename InputIterator>//, typename = required_input_iterator<InputIterator>>
iterator insert(const_iterator pos, InputIterator first, InputIterator last);
};
template <typename T>
List<T>::List(std::initializer_list<T> i_list)
{
insert(end(), i_list.begin(), i_list.end());
}
template<typename T>
template<typename InputIterator>
typename List<T>::iterator List<T>::insert(const_iterator pos, InputIterator first, InputIterator last)
{
//
}
int main()
{
List<int> ll({12, 7, 34, 5});
}
In the constructor the function insert()
is called however the compile throws this error:
error: no matching function for call to 'List<int>::insert(List<int>::iterator, std::initializer_list<int>::const_iterator, std::initializer_list<int>::const_iterator)'
As it shows in the error the compiler is picking the List<int>::iterator
version of end()
when there is a perfect List<int>::const_iterator
version.
If I comment out
// iterator end() noexcept {};
The code works fine.
I have no idea how to fix this error. I think the compiler should pick the right function but it doesn't.
Why this happens and how would it be fixed?
I have searched for similar errors but none of what I found relates to mine.
Upvotes: 0
Views: 405
Reputation: 4715
The non-const
version of an overload is selected if the object is not const
. If this wasn't the case, the non-const
version would never be picked.
iterator
s are required to implicitly convert into const_iterator
s in containers as specified in the standard:
X::iterator ... any iterator category that meets the forward iterator requirements. convertible to X::const_iterator.
So adding a constructor to your const_iterator
should fix your problem in the general case:
class const_iterator {
const_iterator(const iterator&) { /* implement this */ }
};
Upvotes: 1
Reputation: 180415
Inside the body of the constructor, the object is not considered const
. Since it isn't, that mean the non-const version of end
will be called. insert
takes a const_iterator
but the non-const version of end
returns an iterator
, so the code will not compile.
The simplest fix would be to call cend
instead of end
as cend
will always give you a const_iterator
.
A const
qualified member function will only be called if the object it is being called on is const
, or it is the only version of the function. Otherwise the non-const qualified function will be chosen for non-const objects.
Upvotes: 2