Confesso che nemmeno io l'ho compreso appieno, però inizio a racappezzarmi.
Dunque (leggendo da destra a sinistra):
const int* p significa: p è un puntatore a un int costante, quindi si può cambiare dove punta p ma non il valore della variabile a cui punta.
int* const p significa: p è puntatore costante a un int, quindi non si può cambiare dove punta p ma si può cambiare il valore della variabile a cui punta.codice:int i=10; int j = 1000; const int* p = &i; *p = 20; // illegale p = &j; // ok
const int* const p significa: p è puntatore costante a un int costante, quindi non si può cambiare dove punta p, ne si può cambiare il valore della variabile a cui punta.codice:int i=10; int j = 1000; int* const p = &i; *p = 20; // ok p = &j; // illegale
Alla luce di questo, mi sono accorto che la & finale di const int* const& p non serve a niente.codice:int i=10; int j = 1000; const int* const p = &i; *p = 20; // ok p = &j; // illegale
Il compilatore poi non può permette l'assegnazione a un int* di un const int* const per cui serve il const_cast appunto.
Fosse stato un oggetto e non un puntatore non c'erano problemi, visto che viene fatta una copia dell'oggetto e non assegnato un indirizzo.
Sostituisci int* con Nodo* (o Nodo<T>* dove serve) e sei a posto.
Per quanto riguarda il resto.
Non ho trovato spiegazioni sul perché const int*& p non compili.
Penso comunque dipenda dal fatto che, metaforicamente, uno voglia girare a destra, l'altro a sinistra e alla fine vadano a sbattere dritti contro il compilatore.