31

I tried to wrap something similar to Qt's shared data pointers for my purposes, and upon testing I found out that when the const function should be called, its non-const version was chosen instead.

I'm compiling with C++0x options, and here is a minimal code:

struct Data {
    int x() const {
        return 1;
    }
};

template <class T>
struct container
{
    container() {
        ptr = new T();
    }


    T & operator*() {
        puts("non const data ptr");
        return *ptr;
    }

    T * operator->() {
        puts("non const data ptr");
        return ptr;
    }

    const T & operator*() const {
        puts("const data ptr");
        return *ptr;
    }

    const T * operator->() const {
        puts("const data ptr");
        return ptr;
    }

    T* ptr;
};

typedef container<Data> testType;

void testing() {
    testType test;
    test->x();
}

As you can see, Data.x is a const function, so the operator -> called should be the const one. And when I comment out the non-const one, it compiles without errors, so it's possible. Yet my terminal prints:

"non const data ptr"

Is it a GCC bug (I have 4.5.2), or is there something I'm missing?

imz -- Ivan Zakharyaschev
  • 4,921
  • 6
  • 53
  • 104
coyotte508
  • 9,175
  • 6
  • 44
  • 63

4 Answers4

37

If you have two overloads that differ only in their const-ness, then the compiler resolves the call based on whether *this is const or not. In your example code, test is not const, so the non-const overload is called.

If you did this:

testType test;
const testType &test2 = test;
test2->x();

you should see that the other overload gets called, because test2 is const.

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • 6
    so the compiler will prefer to call the non-const overload if the object is not declared const, even if it could call the const overload? – coyotte508 Sep 02 '11 at 17:31
  • 6
    @coyotte508: Precisely. The non-`const` overload is considered a better match. – Oliver Charlesworth Sep 02 '11 at 17:31
  • 6
    Since C++20 you could also do this: `testType test; std::as_const(test).x();` – sandor Jan 14 '21 at 21:04
  • @coyotte508 just out of curiosity, if the compiler preferred the const overload even if the object is not declared const, then what's the point of non-const overloading? – starriet Apr 16 '23 at 01:26
  • @starriet When I wrote the question I had the assumption that the compiler would choose the function based on the return type, eg if I needed a non-const pointer as a return type it would use the non-const function, otherwise the const function. – coyotte508 Apr 17 '23 at 00:31
15

test is a non-const object, so the compiler finds the best match: The non-const version. You can apply constness with static_cast though: static_cast<const testType&>(test)->x();

EDIT: As an aside, as you suspected 99.9% of the time you think you've found a compiler bug you should revisit your code as there's probably some weird quirk and the compiler is in fact following the standard.

Mark B
  • 95,107
  • 10
  • 109
  • 188
2

It doesn't matter whether Data::x is a constant function or not. The operator being called belongs to container<Data> class and not Data class, and its instance is not constant, so non-constant operator is called. If there was only constant operator available or the instance of the class was constant itself, then constant operator would have been called.

1

But testType is not a const object.

Thus it will call the non const version of its members.
If the methods have exactly the same parameters it has to make a choice on which version to call (so it uses the this parameter (the hidden one)). In this case this is not const so you get the non-const method.

testType const test2;
test2->x();  // This will call the const version

This does not affect the call to x() as you can call a const method on a non const object.

Martin York
  • 257,169
  • 86
  • 333
  • 562
  • Could you elaborate on your last sentence? What does it mean _"does not affect the call to x()"_ and _"on a non-const object"_? I thought the `test2` in your code is a const object. By the way, thanks for a clear explanation with the hidden 'this' parameter. – starriet Apr 16 '23 at 01:50