/ / derivato basic_ostream: "utilizzo" parola chiave e sovraccarico ambiguo per operatore << - c ++, ereditarietà, iostream, utilizzo

derivato basic_ostream: parola chiave "using" e sovraccarico ambiguo per operatore << - c ++, ereditarietà, iostream, using

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 № 1

Piuttosto 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).