Newsgroup: it.comp.lang.c++
Titolo: Problemi con operator string() e cout

Qualcuno mi saprebbe dire perche' il seguente codice mi da errore sulla 
riga etichettata con 1 e compila su quella etichettata con 2?
<code>
#include <iostream>
#include <string>
using namespace std;
class A
{
public:
         A (string);
         ~A() {};
         operator string ();
protected:
         string testo;
};
A::A (string x)
         : testo (x)
{
}
A::operator string ()
{
         return testo;
}
int main()
{
         A alfa("alfa");
         cout << alfa << endl;           // 1 Errore
         cout << (string)alfa << endl;   // 2 Qui tutto ok
         return 0;
}
</code>
Compilatore: g++ 2.96 (lo so che devo aggiornarlo)
Io mi sono fatto un'idea, ma non so se e' giusta. In pratica:
esiste operator& string::operator << (ostream&)
esiste A::operator string()
non esiste ::operator << (ostream&, A&)
il g++ non si accorge che facendo static_cast<string>alfa andrebbe tutto ok
Sbaglio? Ma allora, oltre a ridefinire l'operatore <<, non esiste qualche 
altra soluzione?
-- 
Andrea Bergia - studente
Linux Registred User #281550

Andrea Bergia (
andrea...@yahoo.it
), il 19:16, domenica 25 agosto 2002 
scrisse:

Sì: fare ogni volta un cast a std::string.
Saluti
-- 
Per l'e-mail rimouvere gli underscore e la frase in maiuscole.

 Sì: fare ogni volta un cast a std::string.
Fin li' ci arrivavo ;-) infatti l'ho anche fatto nel secondo esempio. Ma 
automatico non c'e' niente? Peccato...


 }
Sì, effettivamente ci si potrebbe aspettare che la riga (1) compili. Dopo
tutto, se usi un oggetto A in altri contesti in cui esiste un overload che
prevede un argomento di tipo std::string, la conversione viene effettuata
implicitamente. Prova, ad esempio, i seguenti:
   std::string s = a;
   s = a;
   s += a;
Inoltre, se definisci una qualsiasi funzioni con questa signature:
   void func( const std::string& s );
vedrai che puoi invocarla con un oggetto A, senza bisogno di alcun cast
esplicito.
(Gli operatori di conversione servono proprio per questo.)
Ciò nondimeno, con l'operatore << la cosa sembra non funzionare.
Devo dire che inizialmente ho anche sospettato fosse un problema del g++, ma
ho subito verificato che anche il compilatore Comeau (che si può provare
online, 
http://www.comeaucomputing.com/tryitout/
) si comporta nello stesso
modo.
Poi, però, mi sono ricordato che l'operatore << che viene  selezionato
quando l'argomento è std::string è in realtà una funzione *template*
dichiarata in questo modo:
 template< typename Char, typename Traits, typename A >
 std::ostream& operator<< ( std::ostream& , const
std::basic_string<Char,Traits,A>& );
(Ricordiamo che std::string è un typedef per std::basic_string<char>.)
Ora, le regole della "template argument deduction" (14.8.2) non consentono
di considerare questa funzione come un possibile candidato per la
risoluzione dell'overload in questione.
Per fare un esempio più semplice. Se abbiamo la seguente funzione template:
 template< typename C, typename T, typename A >
  void func( const basic_string<C,T,A>& s ) { }
non possiamo invocarla usando
   func("pippo");
però avremmo pututo, se func() fosse invece stata
  func( const std::string& s );
Per concludere, se vuoi che il tuo codice compili così com'è, senza alcun
cast esplicito, e senza implementare un apposito operator<< per A, puoi
aggiungere la seguente
 std::ostream& operator<<( std::ostream& os, const std::string& s )
  {
   return  std::operator << <char> ( os, s ); // chiamo esplicit. la func.
template.
  }
Max

Max M. wrote:
[cuttone]
Ok, grazie. Non avendo lo standard sottomano alcune cose mi sfuggivano.


          ~A() {};
[cut]
approfitto del tuo post per una domanda
è necessario, in una classe, specificare il distruttore (anche se
vuoto come nel tuo caso), o viene comunque chiamato quello di
default?
--
Lupin85©
FILSer #2 - Founder di #fils
"It is not important what you believe, only that you believe"

 default?
No, viene chiamato quello di default. Non so perche' l'ho messo, comunque 
in casi come questo e' facoltativo.
