Поток C++ в качестве параметра при перегрузке оператора <<

Я пытаюсь записать свой собственный класс входа и использовать его в качестве потока:

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

Это - код, с которого я запустил:

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

Но я получал ошибку при попытке скомпилировать, высказывании, что не было никакого определения для оператора <<(при использовании станд.:: 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’

Так, я пытался перегрузить оператор <<для принятия этого вида потоков, но он сводит меня с ума. Я не знаю, как сделать это. Я смотрел на, например, определение станд.:: endl в ostream заголовочном файле и записанный функция с этим заголовком:

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

Но никакая удача. Я попробовал те же шаблоны использования вместо того, чтобы непосредственно использовать символ и также попытался просто использовать "константу ostream& OS" и ничто.

Другая вещь, которая ошибки меня - то, что, в выводе ошибок, первом аргументе в пользу оператора <<изменения, иногда это - ссылка на указатель, иногда похожа на двойную ссылку...

10
задан José Tomás Tocino 10 May 2010 в 14:36
поделиться

4 ответа

endl - странный зверь. Это не постоянное значение. На самом деле это функция. Вам нужно специальное переопределение для обработки применения endl:

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

Это позволяет вставить функцию, которая принимает ссылку на ostream и возвращает ссылку на ostream. Вот что такое endl.

Edit: В ответ на интересный вопрос FranticPedantic "почему компилятор не может вывести это автоматически?". Причина в том, что если копнуть еще глубже, то endl на самом деле сама по себе является шаблонной функцией. Она определена так:

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

То есть, она может принимать любой поток в качестве входа и выхода. Проблема не в том, что компилятор не может понять, что T const & может быть указателем функции, а в том, что он не может понять, какой endl вы хотели передать. Шаблонная версия operator<<, представленная в вопросе, примет указатель на любую функцию в качестве второго аргумента, но в то же время шаблон endl представляет бесконечное множество потенциальных функций, поэтому компилятор не может сделать там ничего осмысленного.

Предоставление специальной перегрузки operator<<, второй аргумент которой соответствует конкретному экземпляру шаблона endl, позволяет разрешить вызов.

9
ответ дан 3 December 2019 в 23:12
поделиться

Я считаю, что проблема в том, что ваш поток не перегружает operator << , чтобы принять функцию того же типа, что и std :: endl , как показано в этом ответе: std :: endl имеет неизвестный тип при перегрузке оператора <<

0
ответ дан 3 December 2019 в 23:12
поделиться

В C ++ именно буфер потока инкапсулирует базовый механизм ввода-вывода. Сам поток инкапсулирует только преобразования в строку и направление ввода-вывода.

Таким образом, вам следует использовать один из предопределенных потоковых классов, а не создавать свои собственные. Если у вас есть новая цель, к которой вы хотите перейти (например, системный журнал), то вам следует создать собственный буфер потока (полученный из std :: streambuf ]).

0
ответ дан 3 December 2019 в 23:12
поделиться

endl - это манипулятор ввода-вывода, который представляет собой функтор, который принимает поток по ссылке, выполняет над ним некоторую операцию и возвращает этот поток, также по ссылке. cout << endl эквивалентно cout << '\ n' << flush , где flush - это манипулятор, очищающий выходной буфер.

В вашем классе вам просто нужно написать перегрузку для этого оператора:

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

Где logger & (*) (logger &) - это тип функции, принимающей и возвращающей logger по ссылке. Чтобы написать свои собственные манипуляторы, просто напишите функцию, которая соответствует этой сигнатуре, и попросите ее выполнить некоторую операцию с потоком:

logger& newline(logger& L) {
    return L << '\n';
}
5
ответ дан 3 December 2019 в 23:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: