Newsgroup: it.comp.lang.c++
Titolo: temporary constantness

Supponete di voler scrivere una funzione
ITER findElement(ITER start, KEY key)
che restituisca un iteratore al primo elemento raggiungibile a partire 
da start (mediante incremento) con chiave uguale a key.
Dato che findElement non necessita di modificare alcun elemento, sarebbe 
opportuno che ITER fosse un iteratore costante.
Cosa succede se il chiamante passa un iteratore non costante e ne vuole, 
di conseguenza, ricevere uno non costante?
Qual è il modo più elegante che conoscete per ovviare a questo "problema"?
Kiuhnm

 di conseguenza, ricevere uno non costante?
riceve quello costante e poi lo casta in non costante con
const_cast<ITERATOR>(var)
Ciao

 const_cast<ITERATOR>(var)
Questa č la soluzione banale, ma č anche la piů elegante e sicura?
Se la constantness dipendesse dal contesto, l'iteratore in input e 
qualsiasi sua copia sarebbe const all'interno della funzione, ma 
diventerebbe non const una volta restituita al chiamante.
Kiuhnm


Qualcosa tipo il seguente?
#include <vector>
std::vector<int>::iterator findElement(std::vector<int>::iterator,int key);
std::vector<int>::const_iterator 
findElement(std::vector<int>::const_iterator,int key);
(Ho usato std::vector<int> solo per vedere se compilava, poi userai 
quello che ti serve, con dei template immagino).
Nel caso poi findElement siano funzioni membro, la seconda dovrebbe 
essere dichiarata const.
  bye
	av.

 Qualcosa tipo il seguente?
Direi di no.
Leggi il mio ultimissimo post per capire cosa intendo.
In tale post, generalizzo parlando di due tipi A e B. Per tornare al 
nostro problema, puoi supporre A = iterator e B = const_iterator.
Kiuhnm

Kiuhnm ha scritto:

Si definiscono entrambe le varianti:
iterator findElement(iterator start, KEY key);
const_iterator findElement(const_iterator start, KEY key);
--
Roal Zanazzi

Kiuhnm ha scritto:

Dato che ho risposto nello stesso modo (non avevo visto la risposta di 
Andrea Venturoli):
Il tuo problema specificato in QUESTO thread lo risolverei esattamente 
come abbiamo risposto Andrea ed io.
Se poi tu stavi pensando ad una situazione piu' generale, e' possibile 
che ci sia una soluzione diversa o "piu' generale", ma questo e' un 
altro discorso.
N.B. sul problema specifico di iterator e const_iterator, Scott Meyers 
nel suo "Effective STL" scrive: (Item 26) "Prefer iterator to const 
iterator, reverse_iterator, and const_reverse_iterator."
Nello stesso capitolo si spiega che non e' possibile convertire un 
const_iterator in un iterator con un semplice const_cast<> (come 
erroneamente scritto da Mancuso Raffaele in questo thread).
Quindi nel caso specifico non vedo altre soluzioni semplici oltre alle 
seguenti:
1. forzi l'utilizzatore a passare e ricevere solo iterator, oppure
2. definisci la funzione sia per iterator che per const_iterator.
--
Roal Zanazzi

 2. definisci la funzione sia per iterator che per const_iterator.
Così però f può modificare gli elementi anche se non ne avrebbe bisogno.
A questo punto tanto vale eliminare dal linguaggio la parola "const".
E' una questione di principio! ;-)
Kiuhnm

 const_iterator findElement(const_iterator start, KEY key);
Cosa dice Meyers riguardo a
   void findElement(const_iterator& start, KEY key)
?
Kiuhnm

Kiuhnm ha scritto:

Non saprei, dovremmo chiederlo a lui (oppure dovrei leggermi altri sui 
libri) ;-)
Credo che su "Effective STL" non ci siano riferimenti d'uso di parametri 
di tipo const_iterator& o iterator& (ma potrei sbagliarmi).
Personalmente tenderei a preferire una dichiarazione non ambigua per 
quanto riguarda la semantica della funzione.
Nel caso specifico, avere un parametro const_iterator& start che viene 
modificato dalla funzione e' una ambiguo o almeno poco chiaro.
--
Roal Zanazzi

 
A volte i principi si scontrano con la realta' dei fatti...
--
Roal Zanazzi

 modificato dalla funzione e' una ambiguo o almeno poco chiaro.
Dov'è l'ambiguità?
E' la stessa differenza che si ha tra puntatore costante, puntatore ad 
elementi costanti e puntatore costante ad elementi costanti.
Il reference non è a const quindi è chiaro che la funzione può 
modificare 'start'. Quello che non può fare è modificare gli elementi 
raggiungibili da 'start'.
Giusto per curiosità, ho controllato l'implementazione dell'STL in VC8 
e, come sospettavo (non conosco lo standard in proposito), iterator è 
derivato da const_iterator. Questo fa sì che passare un iterator per 
indirizzo dia il risultato voluto.
Kiuhnm

,std::allocator<std::basic_string<char,std::char_traits<char>,std::allocator<char> > > >' : identifier was truncated to '255' characters in the debug information
Linking...
ciao.exe - 0 error(s), 4 warning(s)
come potete notare tutti i warning si riferiscono alle informazioni di
debug ("identifier was truncated to '255' characters in the debug
information") e neanche un warning al presunto "cast errato".
l'articolo menzionato non l'ho letto e non ho letto la parte dello
standard che si riferisce al cast const_iterator->iterator (se c'è ne
una che specifica che il cast non è possibile), cmq il compilatore
l'ha compilato
Ciao

         const_cast<std::vector<string>::iterator>(iteratore_costante);
Questo uso di const_cast è legittimo soltanto se l'iterator è un typedef di 
un puntatore. Con altri container o anche con diverse implementazioni di 
vector, il codice non compila. GCC e Comeau non lo compilano, ad esempio.
Max

 casualità!!!!!!
Take it easy!
Kiuhnm

> Take it easy!
stavo scherzando :-)

 
Non si tratta di un articolo, ma di un libro (di cui consiglio la 
lettura a tutti coloro siano interessati ad incrementare la propria 
conoscenza della parte della libreria standard del C++ nota come "STL".
Il fatto che un compilatore, notoriamente poco standard-compliant non 
segnali errori o warning per codice non standard e' ininfluente.
--
Roal Zanazzi