C++ Compiler picking the wrong overloaded function

262 views Asked by At

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.

2

There are 2 answers

0
Fatih BAKIR On BEST ANSWER

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.

iterators are required to implicitly convert into const_iterators 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 */ }
};
0
NathanOliver On

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.