In your second example, a non-constant version will be called because no conversion is required, and a call that does not require conversion is a better match than one that requires conversion.
Ultimately, however, you have a major problem: you really need a behavior that changes depending on whether you use your object as an rvalue or lvalue, and const does not actually do that. To make it work correctly, you usually want to return the 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 the normal behavior - when /, if our array<int> (or any type) is const, our operator[] const will be used and it will give const proxy . Since its assignment operators are not constants, an attempt to use them will fail (will not compile).
OTOH, if the original array<int> not const, we will get a non-constant proxy, in which case we can use both operator T and operator= , and be able to read and write the value to array<int> .
source share