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

StackOverflow https://stackoverflow.com/questions/2803403

Вопрос

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

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

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

Итак, я пытался перегрузить оператора << принять этот вид потоков, но это сводит меня с ума. Я не знаю, как это сделать. Например, я был в Локсировании, например, определение STD :: endl в файле заголовка OSTream и написана функция с этим заголовком:

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

Но не повезло. Я пробовал то же самое, используя шаблоны, а не напрямую использую CHAR, а также попробовал просто использовать «Const Ostream & Os», и ничего.

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

Это было полезно?

Решение

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

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

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

Редактировать: В ответ на интересный вопрос о саминдантах «Почему компилятор не может вывести это автоматически?». Причина в том, что если вы еще глубже, endl на самом деле сама шаблон функция. Это определяется как:

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

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

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

Другие советы

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

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top