Newsgroup: it.comp.lang.c++
Titolo: operator int() const o operator const int() ?

Ciao a tutti.
Ho un dubbio con gli operatori di conversione.
Un semplice programma di prova che non fa niente di utile:
#include <iostream>
class Double_to_Int {
	public:
		Double_to_Int(double x = 0): val(x) { }
		operator int() const
		{ std::cout << "operator int() const" << std::endl; return val; }
		operator const int*()
		{ std::cout << "operator const int()" << std::endl; return &val; }
		operator const int()
		{ std::cout << "operator const int()" << std::endl; return val; }
		//operator int() { std::cout << "operator int()" << std::endl;
return val; }
	private:
		int val;
};
int main()
{
	Double_to_Int dti(3.14);
	int x = dti;
	const int y = dti;
	const int *ptr = dti;
	// *ptr = 5;	// errore: ptr punta ad un oggetto const
	std::cout << "x: " << x << std::endl;
	std::cout << "y: " << y << std::endl; // return val
	std::cout << "*ptr: " << *ptr << std::endl; // return &val
	return 0;
}
L'output di questo codice è il seguente:
operator const int()
operator const int()
operator const int()
x: 3
y: 3
*ptr: 3
Ora riflettevo sul fatto che mentre:
operator const int*()
		{ std::cout << "operator const int()" << std::endl; return &val; }
ha senso in quanto converte a const int*
e
operator int() const
		{ std::cout << "operator int() const" << std::endl; return val; }
converte a int impedendo la modifica del membro
La seguente conversione:
operator const int()
		{ std::cout << "operator const int()" << std::endl; return val; }
in che contesto può essere utile?
Grazie ancora.

 in che contesto può essere utile?
Credo in ben pochi, avrebbe forse (forse) senso un «operator const int&()»
(mai provato, comunque userei una funzione invece che un operatore se
proprio dovessi). Quello che viene restituito è un const int, ma visto che
la maggior parte delle volte il codice sarà del tipo:
Double_to_Int oggetto;
int pippo = oggetto + 5;
la costanza dell'int restituito non è importante, perché non viene
modificato. Magari potresti causare un errore di compilazione se usassi
qualcosa come int(oggetto)++.
Ciao,
-Federico

 -Federico
Concordo con quanto hai scritto.
Dato che il risultato finale non cambia abbinerei un
operator int() const ad un int
ed un
operator const int() ad un const int
questo rende, forse, il programma più leggibile?
Non lo so, forse è più un problema di stile, come definire:
int* ptr oppure int *ptr;
Ciao e grazie ancora.

 operator const int() ad un const int
Hm, non credo. Mi pare sia invalso l'uso di scrivere gli operatori di
conversione sempre come:
operator <tipo>() const;
Perché in questo modo si garantisce che la conversione non modifichi
l'oggetto; scrivere «operator const int()» non garantisce l'integrità
dell'oggetto, e comunque il qualificatore const è inutile perché il
risultato viene passato per valore, quindi non ha nessuna possibilità di
influenzare l'oggetto iniziale.
A riprova, usando il tuo codice iniziale e tenendo solo l'operatore const
int():
----------------------------------------
#include <iostream>
class Double_to_Int {
public:
        Double_to_Int(double x = 0): val(int(x)) { }
        operator const int() { std::cout << "operator const int()" << std::endl;
return val; }
private:
        int val;
};
int main()
{
        Double_to_Int dti(3.14);
        int x = dti;
        const int y = dti;
        std::cout << "x: " << x << std::endl;
        std::cout << "y: " << y << std::endl; // return val
        return 0;
}
----------------------------------------
Il codice compila e funziona, sia che dti venga assegnato a int o a const
int.
Ciao,
-Federico

 influenzare l'oggetto iniziale.
In generale restituire un T o un const T non dovrebbe fare molta differenza.
Quando (C++0x) ci saranno gli r-value reference (&&), ci potrebbero essere
situazioni in cui restituire un temporaneo const pregiudica la possibilità
di passare il valore a una certa funzione.
Ad esempio:
 const std::string temp_string1() { return "foo"; }
 std::string       temp_string2() { return "foo"; }
  void func1( std::string&& s );  // rv reference (C++0x)
  void func2( std::string& s );   // reference ordinario
  func1( temp_string1() );  // non compila
  func1( temp_string2() );  // compila!
  func2( temp_string1() );  // non compila
  func2( temp_string2() );  // non compila
Max


Questa non la capisco,
dopo tutto ritorna un const int* dal quale non dovresti essere in grado 
di modificare il valore del membro...
In pratica equivale a ritornare un reference const.
Credo sia buona regola ritornare un reference const o un ptr const ad un 
oggetto interno (a patto che sia chiaro qual'è il "ciclo di vita") 
quando l'oggetto è "abbastanza grosso" (non è il caso dell'OP) e si 
voglia evitare l'overhead della copia del valore.
La differenza tra ptr const vs refernece const è che ptr ti permette di 
tornare anche NULL e/o di assegnare anche dopo l'inizializzazione...
IMHO l'unico porblema è che l'operatore non è dichiarato const.
Io lo avrei dichiarato
operator const int*() const
O sbaglio?
GM

 tornare anche NULL e/o di assegnare anche dopo l'inizializzazione...
Buttare un'eccezione invece? O un assert() ben piazzato?
Ciao,
-Federico

 Buttare un'eccezione invece? O un assert() ben piazzato?
Dipende dai casi.
L'eccezione potrebbe andare bene in certi casi come essere 
sbagliatissima in altri.
E' bene che si conoscano tutte le tecniche e le possibilità offerte dal 
c++, sapendo bene quali implicazioni hanno per poter scegliere la 
migliore caso per caso. Ad esempio per un "getter" di basso livello in 
cui sia da gestire il caso "oggetto non esistente", a occhio sceglierei 
proprio il ritorno di un const ptr (e ci sono in giro decine di librerie 
che scelgono proprio questa strada)...
Sul confronto pointer vs reference esistono tonnellate di discussioni e 
di precisazioni in giro scritte da persone molto più titolate di me.
In certi casi sono praticamente equivalenti, ma in certi casi il ptr ti 
può dare un po di flessibilità (e di "pericolo") in più. Può servire 
(altrimenti eliminavano radicalmente i ptr dal linguaggio ...)
Ciao
GM

 in che contesto può essere utile?
Questa conversione ha esattamente lo stesso effetto di
operator int();
Il const di livello massimo e' ignorato dal compilatore.
Ciao,
Nicola