How to get compiler to prefer const method overloading in C++?
The easiest way to do it would be to make a CAccess
member (Like cbegin
on stdlib containers):
class Example {
public:
int const & Access() const;
int & Access();
int const & CAccess() const { return Access(); }
// No non-const CAccess, so always calls `int const& Access() const`
};
This has the downside that you need to remember to call CAccess
if you don't modify it.
You could also return a proxy instead:
class Example;
class AccessProxy {
Example& e;
explicit AccessProxy(Example& e_) noexcept : e(e_) {}
friend class Example;
public:
operator int const&() const;
int& operator=(int) const;
};
class Example {
public:
int const & Access() const;
AccessProxy Access() {
return { *this };
}
private:
int & ActuallyAccess();
friend class AccessProxy;
};
inline AccessProxy::operator int const&() const {
return e.Access();
}
inline int& AccessProxy::operator=(int v) const {
int& value = e.ActuallyAccess();
value = v;
return value;
};
But the downside here is that the type is no longer int&
, which might lead to some issues, and only operator=
is overloaded.
The second one can easily apply to operator
s, by making a template class, something like this:
#include <utility>
template<class T, class Class, T&(Class::* GetMutable)(), T const&(Class::* GetImmutable)() const>
class AccessProxy {
Class& e;
T& getMutable() const {
return (e.*GetMutable)();
}
const T& getImmutable() const {
return (e.*GetImmutable)();
}
public:
explicit AccessProxy(Class& e_) noexcept : e(e_) {}
operator T const&() const {
return getImmutable();
}
template<class U>
decltype(auto) operator=(U&& arg) const {
return (getMutable() = std::forward<U>(arg));
}
};
class Example {
public:
int const & Access() const;
auto Access() {
return AccessProxy<int, Example, &Example::ActuallyAccess, &Example::Access>{ *this };
}
private:
int & ActuallyAccess();
};
(Though AccessProxy::operator->
would need to be defined too)
and the first method just doesn't work with operator
members (Unless you're willing to change sharedHandle->read()
into sharedHandle.CGet().read()
)