Pergunta

Estou tentando escrever minha própria aula de registro e usá -la como um fluxo:

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

Este é o código com quem comecei:

#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;
}

Mas eu estava recebendo um erro ao tentar compilar, dizendo que não havia definição para o operador << (ao usar o 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’

Então, eu tenho tentado sobrecarregar o operador << para aceitar esse tipo de fluxo, mas está me deixando louco. Eu não sei como fazer isso. Eu tenho lotado, por exemplo, a definição de std :: endl no arquivo de cabeçalho do ostream e escrevi uma função com este cabeçalho:

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

Mas sem sorte. Eu tentei o mesmo usando modelos em vez de usar diretamente, e também tentei simplesmente usar "Const Ostream & OS" e nada.

Outra coisa que me incomoda é que, na saída de erro, o primeiro argumento para o operador << muda, às vezes é uma referência a um ponteiro, às vezes parece uma referência dupla ...

Foi útil?

Solução

endl é uma besta estranha. Não é um valor constante. Na verdade, é, de todas as coisas, uma função. Você precisa de uma substituição especial para lidar com a aplicação de endl:

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

Isso aceita a inserção de uma função que leva um ostream referência e retorna um ostream referência. Isso é o que endl é.

Editar: Em resposta à questão interessante da Frantcedantentic ", por que o compilador não pode deduzir isso automaticamente?". A razão é que, se você se aprofundar ainda mais, endl é realmente um modelo função. É definido como:

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

Isto é, pode levar qualquer tipo de ostream como entrada e saída. Portanto, o problema não é que o compilador não possa deduzir isso T const & pode ser um ponteiro de função, mas que não pode descobrir que endl você pretendia passar. A versão modelada de operator<< apresentado na pergunta aceitaria um ponteiro para qualquer função como seu segundo argumento, mas ao mesmo tempo, o endl modelo representa um infinito Conjunto de funções em potencial, para que o compilador não possa fazer nada significativo lá.

Fornecendo a sobrecarga especial do operator<< cujo segundo argumento corresponde a um específico Instanciação do endl O modelo permite que a chamada seja resolvida.

Outras dicas

endl é um manipulador de IO, que é um functor que aceita um fluxo por referência, executa alguma operação e retorna esse fluxo, também por referência. cout << endl é equivalente a cout << '\n' << flush, Onde flush é um manipulador que libera o buffer de saída.

Na sua classe, você só precisa escrever uma sobrecarga para este operador:

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

Onde logger&(*)(logger&) é o tipo de função aceitar e retornar um logger por referência. Para escrever seus próprios manipuladores, basta escrever uma função que corresponda a essa assinatura e faça com que ela execute alguma operação no fluxo:

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

Eu acredito que o problema é o seu fluxo não sobrecarregar operator<< aceitar uma função que tenha o mesmo tipo que std::endl Conforme ilustrado nesta resposta: std :: endl é do tipo desconhecido quando o operador de sobrecarga <

Em C ++ é o Buffer de fluxo que encapsula o mecanisim de E/S subjacente. O fluxo em si apenas encapsula as conversões em cordas e a direção de E/S.

Assim, você deve usar uma das classes de fluxo predefinidas, em vez de fazer as suas. Se você tem um novo alvo que deseja que seu E/S acesse (como um log do sistema), o que você deve criar é o seu Buffer de fluxo (derivado de std::streambuf).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top