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 sample visitors, one which modifies the visited objects and one which does not.
struct VisitorRead
{
template <class T>
void operator()(T &t) { std::cin >> t; }
};
struct VisitorWrite
{
template <class T>
void operator()(const T &t) { std::cout << t << "\n"; }
};
Now here is an aggregate object - this has just two data members but my actual code is much more complex:
struct Aggregate
{
int i;
double d;
template <class Visitor>
void operator()(Visitor &v)
{
v(i);
v(d);
}
template <class Visitor>
void operator()(Visitor &v) const
{
v(i);
v(d);
}
};
And a function to demonstrate the above:
static void test()
{
Aggregate a;
a(VisitorRead());
const Aggregate b(a);
b(VisitorWrite());
}
Now, the problem here is the duplication of Aggregate::operator()
for const
and non-const
versions.
Is it somehow possible to avoid duplication of this code?
I have one solution which is this:
template <class Visitor, class Struct>
void visit(Visitor &v, Struct &s)
{
v(s.i);
v(s.i);
}
static void test2()
{
Aggregate a;
visit(VisitorRead(), a);
const Aggregate b(a);
visit(VisitorWrite(), b);
}
This means neither Aggregate::operator()
is needed and there is no duplication. But I am not comfortable with the fact that visit()
is generic with no mention of type Aggregate
.
Is there a better way?
const
method or taking aconst
variable send a very strong message: "this method doesn't make changes!" Yet having a version that does change things simply means that it will get called in its place. This will only lead to confusion, and eventually bugs. – Hybridismconst
version ofAggregate::operator ()
? – Slitconst Aggregate
asb
intest()
. – JussiveAggregate
? The STL does quite a bit of that... just naming the argument asForwardIterator
and expect that user code knows what to do. Alternatively, you could use SFINAE to detect whether the argument is actually aAggregate
or not. – ExsiccateAggregate
, then following the interface principle they do belong to the same type...) – Exsiccate