Domanda

Sto cercando di scrivere la mia classe di log e usarlo come un flusso:

logger L;
L << "whatever" << std::endl;

Questo è il codice che ho iniziato con:

#include <iostream>

using namespace std;


class logger{
public:
    template <typename T>
    friend logger& operator <<(logger& log, const T& value);
};

template <typename T>
logger& operator <<(logger& log, T const & value) {
    // Here I'd output the values to a file and stdout, etc.
    cout << value;
    return log;
}

int main(int argc, char *argv[])
{
    logger L;
    L << "hello" << '\n' ; // This works
    L << "bye" << "alo" << endl; // This doesn't work
    return 0;
}

Ma stavo ottenendo un errore quando si cerca di compilare, dicendo che non vi era alcuna definizione per l'operatore << (quando si utilizza std :: endl):

pruebaLog.cpp:31: error: no match for ‘operator<<’ in ‘operator<< [with T = char [4]](((logger&)((logger*)operator<< [with T = char [4]](((logger&)(& L)), ((const char (&)[4])"bye")))), ((const char (&)[4])"alo")) << std::endl’

Così, ho cercato di operatore di sovraccarica << ad accettare questo tipo di corsi d'acqua, ma mi sta facendo impazzire. Io non so come farlo. Sono stato loking a, per esempio, la definizione di std :: endl al file di intestazione ostream e scritto una funzione con questa intestazione:

logger& operator <<(logger& log, const basic_ostream<char,char_traits<char> >& (*s)(basic_ostream<char,char_traits<char> >&))

, ma senza fortuna. Ho provato la stessa utilizzando i modelli, invece di usare direttamente char, e anche provato semplicemente utilizzando "const ostream & os", e nulla.

Un'altra cosa che mi bug è che, in uscita di errore, il primo argomento per l'operatore << cambiamenti, a volte è un riferimento a un puntatore, a volte si presenta come un doppio riferimento ...

È stato utile?

Soluzione

endl è una strana bestia. Non è un valore costante. In realtà, di tutte le cose, una funzione. Hai bisogno di una sostituzione speciale per gestire l'applicazione di endl:

logger& operator<< (logger& log, ostream& (*pf) (ostream&))
{
  cout << pf;
  return log;
}

Questa accetta l'inserimento di una funzione che riceve un riferimento ostream e restituisce un riferimento ostream. Questo è ciò che è endl.

Modifica In risposta alla domanda interessante di FranticPedantic di "Perché non è possibile il compilatore dedurre automaticamente?". La ragione è che se si approfondire ancora più in profondità, endl è in realtà di per sé un modello la funzione. E 'definito come:

template <class charT, class traits>
  basic_ostream<charT,traits>& endl ( basic_ostream<charT,traits>& os );

Cioè, si può prendere qualsiasi tipo di ostream come input e output. Quindi il problema non è che il compilatore non può dedurre che T const & potrebbe essere un puntatore a funzione, ma che non riesce a capire che endl si intende passare in. La versione su modelli di operator<< presentato nella questione avrebbe accettato un puntatore a qualsiasi funzione come secondo argomento, ma, allo stesso tempo, il modello endl rappresenta un infinito insieme di potenziali funzioni, in modo che il compilatore non può fare qualcosa di significativo lì.

Fornire la speciale sovraccarico del operator<< il cui argomento secondo corrisponde a un specifica esemplificazione del modello endl permette la chiamata a risolvere.

Altri suggerimenti

endl è un manipolatore IO, che è un functor che accetta un flusso per riferimento, esegue alcune operazioni su di esso, e restituisce tale flusso, anche mediante riferimento. cout << endl equivale a cout << '\n' << flush, dove flush è un manipolatore che svuota il buffer di uscita.

Nella classe, basta scrivere un sovraccarico per questo operatore:

logger& operator<<(logger&(*function)(logger&)) {
    return function(*this);
}

Dove logger&(*)(logger&) è il tipo di funzione accettare e restituire un logger per riferimento. Per scrivere i propri manipolatori, basta scrivere una funzione che le partite che la firma, e lo hanno eseguire alcune operazioni sul flusso:

logger& newline(logger& L) {
    return L << '\n';
}

Io credo che il problema è il vostro flusso di non sovraccaricare operator<< ad accettare una funzione che ha lo stesso tipo std::endl come illustrato in questa risposta: std :: endl è di tipo sconosciuto quando il sovraccarico operatore <<

In C ++ è il flusso tampone che incapsula il sottostante / O mechanisim I. Corrente stessa incapsula solo le conversioni stringa e la direzione di I / O.

In questo modo si dovrebbe utilizzare una delle classi stream predefiniti, piuttosto che fare il proprio. Se si dispone di un nuovo bersaglio volete che il vostro I / O per andare a (come un log di sistema), ciò che si dovrebbe essere la creazione è il tuo flusso di buffer (derivato da std::streambuf).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top