开发者

C++ compiler picking the wrong overload of a class member function

开发者 https://www.devze.com 2023-03-29 00:53 出处:网络
I have this code: template <class T> class Something { T val; public: inline Something() : val() {} inline Something(T v) : val(v) {}

I have this code:

template <class T>
class Something
{
    T val;
public:
    inline Something() : val() {}
    inline Something(T v) : val(v) {}
    inline T& get() const { return val; }

    inline Something& operator =(const Something& a) { val = a.val; return *this; }
};

typedef Something<int> IntSomething;
typedef Something<const int> ConstIntSomething;

class Other
{
public:
    IntSomething some_function()
    {
        return IntSomething(42);
    }

    ConstIntSomething some_function() const
    {
    开发者_如何学C    return ConstIntSomething(42);
    }
};

void wtf_func()
{
    Other o;
    ConstIntSomething s;
    s = o.some_function();
}

However, the compiler picks the wrong overload of Other::some_function() in wtf_func() (i.e. the non-const one). How can I fix this? Note that for certain reasons I cannot change the name of Other::some_function().


o is not const-qualified, so the non-const some_function is selected. If you want to select the const-qualified overload, you need to add the const qualifier to o:

Other o;
Other const& oref(o);
ConstIntSomething s;
s = oref.some_function();

When overload resolution occurs, the compiler only looks at the o.some_function() subexpression; it does not look at the context around the function call to decide to pick something else. Further, the return type of a member function is not considered during overload resolution.

Note that it may make more sense for IntSomething to be implicitly convertible to ConstIntSomething, either using an operator ConstIntSomething() overload in IntSomething (less good) or using a non-explicit ConstIntSomething(IntSomething const&) constructor in ConstIntSomething (more good).


It doesn't pick the wrong overload; const-ness is resolved by whether this is const or not. In your case, o is non-const, so the non-const overload is picked.

You can hack this by creating a const-reference to o, e.g.:

const Other &o2 = o;
s = o2.some_function();

But really, you should probably be considering your overloads in Something. For instance, you can't currently do this:

IntSomething x;
ConstIntSomething y;
y = x;

which doesn't sound correct. Why shouldn't you be allowed to take a const ref to a non-const ref?


Your object o needs to be const object for a const function to be called on it. Otherwise the compiler rightly picks up the non const version of the function.


The compiler picks the overload to use based on the constness of the object that will become this. You can make it call the desired version with static_cast: s = static_cast<const Other&>(o.some_function());


You might also want to copy the new behaviour found in the containers of the C++0x standard library. Containers such as vector now have members cbegin() and cend() that return a const_iterator whether the container is const or not unlike begin() and end()

class Other {
    // Rest of other
public:
    // No overload for non-const
    // Even if called with a non const Other, since this member is marked
    // const, this will be of type Other const * in all cases and will call
    // the const qualified overload of some_function.
    ConstIntSomething csome_function() const
    {
        return some_function();
    }
};
0

精彩评论

暂无评论...
验证码 换一张
取 消