Re: an "optional const"
On Sep 15, 6:40 pm, "Alf P. Steinbach" <al...@start.no> wrote:
[...]
* Victor Bazarov:
AFAIK, folks who are sure that the 'do something' parts in those two
functions do not differ at all, simply write a const version and in the
non-const version do the const_cast in and out:
Effectively, yes, but regarding syntax they try to avoid 'const_cast'.
[...]
One general code reuse scheme goes like this:
private:
ReturnType& fooImpl() const ...
public:
ReturnType& foo() { return fooImpl(); }
ReturnType const& foo() const { return fooImpl(); }
While this is often an acceptable solution it is not general. If
fooImpl should need to call other member functions with overload
resolution based on the constness of the object, then this solution
wont work. See code below.
Also, if fooImpl needs to return a reference to a member, as often is
the case, you still need a const_cast inside the implementation; since
fooImpl is const while the return value is not. In that case this
solution is no better than the cast'n'forward idiom.
The fully general and safe solution is to forward to a template
function:
// Const and non-const getter overloads
#include <iostream>
using namespace std;
typedef int X;
class C {
X x_;
public:
C () {}
void foo () {cout << "non-const\n";}
void foo () const {cout << "const\n";}
X& get () {
foo ();
return x_;
}
#if 0 // duplicate algorithm
const X& get () const {
foo ();
return x_;
}
#else // dangerous cast'n'forward idiom
const X& get () const {
return const_cast <C*> (this)->get ();
}
#endif
// safe template solution
#if 1 // C++98
X& get2 () {return do_get2 <X> (*this);}
const X& get2 () const {return do_get2 <const X> (*this);}
template <class R, class This>
static R& do_get2 (This& self) {
self.foo ();
return self.x_;
}
#else // C++0x
X& get2 () {return do_get2 (*this);}
const X& get2 () const {return do_get2 (*this);}
template <class This>
static auto do_get2 (This& self) -> decltype (self.x_)& {
self.foo ();
return self.x_;
}
#endif
};
void test_getter_overload ()
{
cout << "Non-const object tests:\n";
C c;
c.get (); // Ok, prints "non-const".
c.get2 (); // Ok, prints "non-const".
cout << "Const object tests:\n";
const C cc;
cc.get (); // Ouch, prints "non-const".
cc.get2 (); // Ok, prints "const".
}
Regards,
Vidar Hasfjord