Внедрение no-op std:: ostream
Я смотрю на создание класса ведения журнала, в котором есть такие элементы, как Info, Error и т.д., Которые можно настраивать для вывода на консоль, в файл или в никуда.
Для эффективности я хотел бы избежать накладных расходов на форматирование сообщений, которые будут выбрасываться (т.е. информационные сообщения, когда они не работают в подробном режиме). Если я реализую собственный std :: streambuf, который выводит в никуда, я представляю, что слой std :: ostream все равно будет выполнять все форматирование. Может кто-нибудь предложить способ получить действительно "нулевой" std :: ostream, который вообще не будет выполнять какую-либо работу с параметрами, передаваемыми ему с помощью <<
?
Ответы
Ответ 1
Чтобы запретить operator<<()
выполнять форматирование, вы должны знать тип потока во время компиляции. Это можно сделать с помощью макросов или шаблонов.
Мой шаблон решения следует.
class NullStream {
public:
void setFile() { /* no-op */ }
template<typename TPrintable>
NullStream& operator<<(TPrintable const&)
{ return *this; } /* no-op */
}
template<class TErrorStream> // add TInfoStream etc
class Logger {
public:
TErrorStream& errorStream() {
return m_errorStream;
}
private:
TErrorStream m_errorStream;
};
//usage
int main() {
Logger<std::ofstream> normal_logger; // does real output
normal_logger.errorStream().open("out.txt");
normal_logger.errorStream() << "My age is " << 19;
Logger<NullStream> null_logger; // does zero output with zero overhead
null_logger.errorStream().open("out.txt"); // no-op
null_logger.errorStream() << "My age is " << 19; // no-op
}
Поскольку вы должны сделать это во время компиляции, это, конечно, довольно негибко.
Например, вы не можете определить уровень ведения журнала во время выполнения из файла конфигурации.
Ответ 2
Быстрое google придумало этот пример, который может быть полезен. Я не предлагаю никаких гарантий, кроме того, что он компилируется и запускается: -)
#include <streambuf>
#include <ostream>
template <class cT, class traits = std::char_traits<cT> >
class basic_nullbuf: public std::basic_streambuf<cT, traits> {
typename traits::int_type overflow(typename traits::int_type c)
{
return traits::not_eof(c); // indicate success
}
};
template <class cT, class traits = std::char_traits<cT> >
class basic_onullstream: public std::basic_ostream<cT, traits> {
public:
basic_onullstream():
std::basic_ios<cT, traits>(&m_sbuf),
std::basic_ostream<cT, traits>(&m_sbuf)
{
init(&m_sbuf);
}
private:
basic_nullbuf<cT, traits> m_sbuf;
};
typedef basic_onullstream<char> onullstream;
typedef basic_onullstream<wchar_t> wonullstream;
int main() {
onullstream os;
os << 666;
}
Ответ 3
все, спасибо за обмен кодом, я просто делаю тест, тогда метод Neil все равно будет выполнять форматирование строк, например:
#include <streambuf>
#include <ostream>
#include <iostream>
using namespace std;
template <class cT, class traits = std::char_traits<cT> >
class basic_nullbuf: public std::basic_streambuf<cT, traits> {
typename traits::int_type overflow(typename traits::int_type c)
{
return traits::not_eof(c); // indicate success
}
};
template <class cT, class traits = std::char_traits<cT> >
class basic_onullstream: public std::basic_ostream<cT, traits> {
public:
basic_onullstream():
std::basic_ios<cT, traits>(&m_sbuf),
std::basic_ostream<cT, traits>(&m_sbuf)
{
init(&m_sbuf);
}
private:
basic_nullbuf<cT, traits> m_sbuf;
};
typedef basic_onullstream<char> onullstream;
typedef basic_onullstream<wchar_t> wonullstream;
class MyClass
{
int a;
friend ostream& operator<< (ostream&, MyClass const&);
};
ostream& operator<<(ostream& out,MyClass const& b)
{
std::cout<<"call format function!!";
out << b.a;
return out;
}
int main() {
onullstream os;
MyClass obj;
os<<obj;
}
Запустив эту программу, вы обнаружите, что вызывается "ostream & operator < (ostream & out, MyClass const & b)". Таким образом, выполнение формата на obj все равно будет вызвано. Таким образом, мы все еще не можем избежать накладных расходов на форматирование сообщений.
Ответ 4
Вероятно, вам понадобится больше, чем просто форматирование текста и фильтрация сообщений. Как насчет многопоточности?
Я бы выполнил синхронизацию фильтрации и многопоточности как ответственность отдельного класса.
Однако регистрация - непростая задача, и я бы попытался использовать существующие решения для ведения журналов, вместо того, чтобы разрабатывать новую.
Ответ 5
Почему бы не использовать существующие решения для ведения журналов, используемые миллионами пользователей?
log4j, log4net, log4cxx.., чтобы назвать несколько...