C ++ Stream в качестве параметра при перегрузке оператора <<
-
25-09-2019 - |
Вопрос
Я пытаюсь написать свой собственный класс регистрации и использовать его как поток:
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
).