I have a problem with duplication of identical code for const
and non-const
versions. I can illustrate the problem with some code. Here are two s
Since your ultimate implementations are not always identical, I don't think there's a real solution for your perceived "problem".
Let's think about this. We have to cater for the situations where Aggregate
is either const or non-const. Surely we should not relax that (e.g. by providing only a non-const version).
Now, the const-version of the operator can only call visitors which take their argument by const-ref (or by value), while the non-constant version can call any visitor.
You might think that you can replace one of the two implementations by the other. To do so, you would always implement the const version in terms of the non-const one, never the other way around. Hypothetically:
void operator()(Visitor & v) { /* #1, real work */ }
void operator()(Visitor & v) const
{
const_cast(this)->operator()(v); // #2, delegate
}
But for this to make sense, line #2 requires that the operation is logically non-mutating. This is possible for example in the typical member-access operator, where you provide either a constant or a non-constant reference to some element. But in your situation, you cannot guarantee that the operator()(v)
call is non-mutating on *this
!
Therefore, your two functions are really rather different, even though they look formally similar. You cannot express one in terms of the other.
Maybe you can see this another way: Your two functions aren't actually the same. In pseudo-code, they are:
void operator()(Visitor & v) {
v( (Aggregate *)->i );
v( (Aggregate *)->d );
}
void operator()(Visitor & v) const {
v( (const Aggregate *)->i );
v( (const Aggregate *)->d );
}
Actually, coming to think of it, perhaps if you're willing to modify the signature a bit, something can be done:
template
void visit(Visitor & v)
{
typedef typename std::conditional::type this_p;
v(const_cast(this)->i);
v(const_cast(this)->d);
}
void operator()(Visitor & v) { visit<>(v); }
void operator()(Visitor & v) const { const_cast(this)->visit()(v); }