Немного более многословно, чем Мейерс, но я мог бы сделать это:
class X {
private:
// This method MUST NOT be called except from boilerplate accessors.
Z &_getZ(size_t index) const {
return something;
}
// boilerplate accessors
public:
Z &getZ(size_t index) { return _getZ(index); }
const Z &getZ(size_t index) const { return _getZ(index); }
};
Закрытый метод имеет нежелательное свойство, что он возвращает неконстантный Z & для константного экземпляра, поэтому он является закрытым. Частные методы могут нарушать инварианты внешнего интерфейса (в этом случае желаемый инвариант - «объект const не может быть изменен через ссылки, полученные через него на объекты, которые он имеет -a»).
Обратите внимание, что комментарии являются частью шаблона. Интерфейс _getZ указывает, что его никогда нельзя назвать действительным (за исключением средств доступа, очевидно): в любом случае, это не представляется очевидным преимуществом, потому что вводить его будет еще 1 символ и не будет результат в меньшем или более быстром коде. Вызов метода эквивалентен вызову одного из методов доступа с const_cast, и вам бы этого тоже не хотелось. Если вы беспокоитесь о том, чтобы сделать ошибки очевидными (и это справедливая цель), тогда назовите это const_cast_getZ вместо _getZ.
Кстати, я ценю решение Мейерса. У меня нет философских возражений против этого. Лично я предпочитаю немного контролируемого повторения и частный метод, который должен вызываться только в определенных строго контролируемых обстоятельствах, а не метод, похожий на шум линии. Выберите свой яд и придерживайтесь его.
[Редактировать: Кевин справедливо указал, что _getZ, возможно, захочет вызвать еще один метод (скажем, generateZ), который специализируется на const так же, как getZ. В этом случае _getZ увидит const Z & и будет вынужден const_cast перед возвращением. Это все еще безопасно, так как шаблонный аксессуар контролирует все, но не совсем очевидно, что это безопасно. Кроме того, если вы сделаете это, а затем измените generateZ, чтобы он всегда возвращал const, вам также нужно изменить getZ, чтобы он всегда возвращал const, но компилятор не скажет вам, что вы делаете.
Это последнее замечание о компиляторе также верно для рекомендованного Мейерса шаблона, но первое замечание относительно неочевидного const_cast - нет. Таким образом, в итоге я думаю, что если _getZ окажется нужным const_cast для своего возвращаемого значения, то этот шаблон теряет большую часть своего значения по сравнению с Мейерсом. Поскольку он также страдает недостатками по сравнению с Мейерсом, я думаю, что я бы переключился на его в этой ситуации. Рефакторинг от одного к другому легко - он не влияет на любой другой допустимый код в классе, так как только неверный код и шаблон вызывают _getZ.]