lo tolmencre
lo tolmencre

Reputation: 3934

overloading signature identical methods with const keyword

I wondered how std::vector::begin() or similar methods could actually be overloaded for different return types (const and non const iterators), as in std::vector<int>::iterator it = vect.begin(); and std::vector<int>::const_iterator cit = vect.begin();

Because, functions that differ only in their return type cannot be overloaded. Then I had a peek into stl_vector.h and found that this is possible because of one of the functions is const.

324      /**                                                                       |   
325       *  Returns a read/write iterator that points to the first                |   
326       *  element in the %vector.  Iteration is done in ordinary                |   
327       *  element order.                                                        |   
328       */                                                                       |   
329      iterator                                                                  |   
330      begin()                                                                   |   
331      { return iterator(this->_M_impl._M_start); }                              |   
332                                                                                |   
333      /**                                                                       |   
334       *  Returns a read-only (constant) iterator that points to the            |   
335       *  first element in the %vector.  Iteration is done in ordinary          |   
336       *  element order.                                                        |   
337       */                                                                       |   
338      const_iterator                                                            |   
339      begin() const                                                             |   
340      { return const_iterator(this->_M_impl._M_start); }                        |   
341                                                                                |   
342      /**                                                                       |   
343       *  Returns a read/write iterator that points one past the last           |   
344       *  element in the %vector.  Iteration is done in ordinary                |   
345       *  element order.                                                        |   
346       */                                                                       | 

Then I tried mimicking this structure in a test program, but am getting an error which puzzles me, as the logic looks identical to me:

struct A
{
};

struct B
{
};


struct C
{
    A f() const {
        std::cout << "A" << "\n";
        return A();
    }
    B f() {
        std::cout << "B" << "\n";
        return B();
    }
};


int main(){
    C c;
    A x = c.f();
}

error: no viable conversion from 'B' to 'A' A x = c.f();

The method returning a B is called, why doesn't the compiler deduce from A x that the other method needs to be called and what is the difference between my test program and the stl_vector code?

Upvotes: 2

Views: 64

Answers (1)

juanchopanza
juanchopanza

Reputation: 227418

You're not seeing an overload, but rather, a conversion between the relevant iterator and const_iterator types:

std::vector<int>::const_iterator cit = vect.begin();

If vect is non-const, then vect.begin() returns a vector<int>::iterator, which can then be converted to vector<int>::const_iterator. The reverse conversion is not allowed, for const correctness reasons.

This is largely unrelated to the issue of const qualification of member functions, which does permit overloading.

Upvotes: 2

Related Questions