Un po 'più prolisso di Meyers, ma potrei farlo:
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); }
};
Il metodo privato ha la proprietà indesiderabile che restituisce una Z non costante e per un'istanza const, motivo per cui è privata. I metodi privati possono spezzare gli invarianti dell'interfaccia esterna (in questo caso l'invariante desiderato è "un oggetto const non può essere modificato tramite riferimenti ottenuti attraverso di esso con oggetti che ha-a").
Nota che i commenti fanno parte del modello - l'interfaccia di _getZ specifica che non è mai valido chiamarlo (a parte gli accessi, ovviamente): non c'è comunque alcun vantaggio immaginabile farlo, perché è 1 carattere in più da digitare e non lo farà risulta in un codice più piccolo o più veloce. Chiamare il metodo equivale a chiamare uno degli accessor con un const_cast e non vorrai farlo neanche tu. Se sei preoccupato di rendere evidenti gli errori (e questo è un obiettivo equo), chiamalo const_cast_getZ invece di _getZ.
A proposito, apprezzo la soluzione di Meyers. Non ho obiezioni filosofiche. Personalmente, però, preferisco un po 'di ripetizione controllata e un metodo privato che deve essere chiamato solo in determinate circostanze strettamente controllate, rispetto a un metodo che assomiglia al rumore di linea. Scegli il tuo veleno e attaccalo.
[Modifica: Kevin ha giustamente sottolineato che _getZ potrebbe voler chiamare un ulteriore metodo (diciamo generateZ) che è specializzato nello stesso modo di getZ. In questo caso, _getZ visualizzerà una const Z e dovrà trasmetterla prima di tornare. È ancora sicuro, dal momento che l'accessorio della piastra di caldaia controlla tutto, ma non è straordinariamente ovvio che sia sicuro. Inoltre, se lo fai e successivamente cambi generateZ per restituire sempre const, allora devi anche cambiare getZ per restituire sempre const, ma il compilatore non ti dirà che lo fai.
Quest'ultimo punto sul compilatore è vero anche per il modello raccomandato da Meyers, ma il primo punto su un const_cast non ovvio non lo è. Quindi, a conti fatti, penso che se _getZ risulta avere bisogno di un const_cast per il suo valore di ritorno, allora questo modello perde molto del suo valore rispetto a quello di Meyers. Dato che soffre anche di svantaggi rispetto a quelli di Meyers, penso che passerei al suo in quella situazione. Il refactoring dall'uno all'altro è semplice: non influisce su nessun altro codice valido nella classe, poiché solo il codice non valido e la piastra della caldaia chiamano _getZ.]