Ho una classe derivata basic_ostream e unmodificatore inline (simile a setw). La mia classe di flusso dovrebbe anche ereditare tutto il comportamento dell'operatore << dal suo genitore. Ricevo diversi errori del compilatore a seconda che io utilizzi o meno la parola chiave "using":
#include <iostream>
struct modifier { };
template <typename C, typename T=std::char_traits<C> >
struct mystream : public std::basic_ostream<C, T>
{
// this is where the trouble is
using std::basic_ostream<C, T>::operator <<;
inline mystream & operator << (const modifier & mod)
{
// ...custom behavior...
return *this;
}
};
int main()
{
mystream<char> foo;
modifier m;
foo << "string"; // this fails if the using is present
foo << 123; // this fails if the using is absent
foo << m;
}
Quando inserisco la direttiva using, il compilatoreè confuso sull'output "stringa", e se lo commento, viene confuso sull'output 123 intero, in entrambi i casi mi dà "errore: sovraccarico ambiguo per" operatore << "". Ho il problema con g ++ 4.2.1 e g ++ 4.8. Qual è la strada giusta da seguire qui?
risposte:
3 per risposta № 1Piuttosto quindi eredita da std :: basic_ostream, non sarà sufficiente reimplementare << per la tua struttura di modifica usando un flusso regolare:
std::ostream & operator << (std::ostream &stream, const modifier & mod)
{
// ...custom behavior...
return stream;
}
La tua soluzione sembra complicata, ma penso che l'errore reale che ricevi provenga dal tuo sovraccarico di << - deve accettare due argomenti (il primo argomento è il riferimento allo stream stesso).
2 per risposta № 2
Senza il using
, è chiaro: il compilatore non ne troverà nessuno dei sovraccarichi membri di <<
, perché la tua funzione si nasconde loro. Il <<
è un membro, quindi senza il using
, si scompare. Il <<
non è un membro, quindi funziona ancora.
Quando aggiungi il using
: tutti i sovraccarichi dei membri sono visibile, come se erano membri della tua classe. E
"string"
sarà convertito in a char const*
. Il sovraccarico che il compilatore sta cercando di risolvere è:
operator<<( mystream<char>, char const* ).
Consideriamo ora alcuni dei sovraccarichi da considerare:
std::ostream& mystream::operator<<( void const* );
std::ostream& mystream::operator<<( bool );
std::ostream& operator<<( std::ostream&, char const* );
Per il primo argomento (foo
, a mystream
), i primi due entrambe le funzioni corrispondono meglio della terza (poiché lo sono una corrispondenza esatta); per il secondo argomento (la stringa letterale), la terza funzione è una corrispondenza migliore. Quindi: ambiguo.
Più in generale, ci sono diversi problemi con il tuo codice. Fondamentalmente, lo fai non Inserisci <<
operatori derivando. Come vedi, non funziona. Forse più significativamente, qualcosa piace:
foo << 123 << m;
non funzionerà, perché foo << 123
restituisce a std::ostream&
, non a mystream
, e c'è no <<
che funzionerà con un
std::ostream&
e a modifier
. Aggiungi <<
operatori di definizione di nuove funzioni gratuite:
std::ostream&
operator<<( std::ostream& dest, modifier const& other )
{
// ...
return *this;
}
Se hai bisogno di ulteriori dati per formattare, usi xalloc
e
iword
o pword
per ottenerlo, ad es. per definire un manipolatore:
static int Modifier::modIndex = std::ostream::xalloc();
class mod1
{
int myModifier;
public:
mod1( int m ) : myModifier( m ) {}
friend std::ostream& operator<<( std::ostream& dest,
mod1 const& mod )
{
dest.iword( modIndex ) = myModifier;
return *this;
}
};
Quindi accedi dest.iword( modIndex )
per ottenere queste informazioni nella routine di output.
iword()
restituisce a long&
, diverso per ogni istanza del tuo stream (e per ogni diverso indice che usi).
Se hai bisogno di maggiori informazioni, puoi usare pword
invece di
iword
-pword
restituisce un riferimento a a void*
. Se tu vuoi usarlo per puntare alla memoria allocata dinamicamente, don "t dimentica di registrare un callback per eliminarlo (usando
ios_base::register_callback
).