In your second example, the non-const version will be called, because no conversion is required, and a call that requires no conversion is a better match than one that requires a conversion.
Ultimately, however, you have a basic problem here: what you really want is behavior that changes depending on whether you're using your object as an rvalue or an lvalue, and const
doesn't really do that. To make it work correctly, you normally want to return a proxy object, and overload operator=
and operator T
for the proxy object:
template <class T>
class myarray {
T *ptr;
class proxy {
T &val;
proxy &operator=(proxy const &p); // assignment not allowed.
public:
proxy(T &t) : val(t) {}
operator T() const { return val; }
proxy &operator=(T const&t) { val = t; return *this; }
};
proxy const operator[](int sub) const { return proxy(ptr[sub]); }
proxy operator[](int sub) { return proxy(ptr[sub]); }
// obviously other stuff like ctors needed.
};
Now we get sane behavior -- when/if our array<int>
(or whatever type) is const, our operator[] const
will be used, and it'll give a const proxy
. Since its assignment operators are not const, attempting to use them will fail (won't compile).
OTOH, if the original array<int>
was not const, we'll get a non-const proxy, in which case we can use both operator T
and operator=
, and be able to both read and write the value in the array<int>
.