Поскольку ваши конечные реализации не всегда идентичны, я не думаю, что есть реальное решение для вашей воспринятой "проблемы".
Давайте подумаем об этом.Мы должны учитывать ситуации, когда Aggregate
является постоянным или неконстантным.Конечно, мы не должны ослаблять это (например, предоставляя только неконстантную версию).
Теперь const-версия оператора может вызывать только тех посетителей, которые принимают аргумент через const-ref (или по значению)в то время как неконстантная версия может вызывать любого посетителя.
Можно подумать, что вы можете заменить одну из двух реализаций другой.Для этого вы всегда должны реализовывать константную версию в терминах неконстантной, а не наоборот.Гипотетически:
void operator()(Visitor & v) { /* #1, real work */ }
void operator()(Visitor & v) const
{
const_cast<Aggregate *>(this)->operator()(v); // #2, delegate
}
Но для того, чтобы это имело смысл, строка № 2 требует, чтобы операция логически была неизменной.Это возможно, например, в типичном операторе доступа к элементу, где вы предоставляете постоянную или непостоянную ссылку на некоторый элемент.Но в вашей ситуации вы не можете гарантировать, что вызов operator()(v)
не является мутирующим для *this
!
Следовательно, ваши две функции действительно довольно разные, даже если они выглядят формально похожими.Вы не можете выразить одно через другое.
Может быть, вы можете увидеть это по-другому: ваши две функции на самом деле не совпадают.В псевдокоде это:
void operator()(Visitor & v) {
v( (Aggregate *)->i );
v( (Aggregate *)->d );
}
void operator()(Visitor & v) const {
v( (const Aggregate *)->i );
v( (const Aggregate *)->d );
}
На самом деле, если задуматься, возможно, если вы захотите немного изменить подпись, что-то можно сделать:
template <bool C = false>
void visit(Visitor & v)
{
typedef typename std::conditional<C, const Aggregate *, Aggregate *>::type this_p;
v(const_cast<this_p>(this)->i);
v(const_cast<this_p>(this)->d);
}
void operator()(Visitor & v) { visit<>(v); }
void operator()(Visitor & v) const { const_cast<Aggregate *>(this)->visit<true>()(v); }