2009-03-23 3 views
10

Как я могу вывести класс из cout, так что, например, запись на негоподгоняет COUT

new_cout << "message";

будет эквивалентно

cout << __FUNCTION__ << "message" << "end of message" << endl;

ответ

29
class Log 
{ 
public: 
    Log(const std::string &funcName) 
    { 
     std::cout << funcName << ": "; 
    } 

    template <class T> 
    Log &operator<<(const T &v) 
    { 
     std::cout << v; 
     return *this; 
    } 

    ~Log() 
    { 
     std::cout << " [end of message]" << std::endl; 
    } 
}; 

#define MAGIC_LOG Log(__FUNCTION__) 

Следовательно:

MAGIC_LOG << "here's a message"; 
MAGIC_LOG << "here's one with a number: " << 5; 
+0

+1. В отличие от всех ответов, которые просто говорят «переопределить оператор <<()», это решение устраняет тот факт, что верхний и нижний колонтитулы должны выводиться один раз за оператор, а не один раз за <<. –

+0

+1 действительно, хорошая идея. просто что-то о endl: я подозреваю, что для отладочного сообщения, endl редко требуется, но если вы хотите, чтобы он мог вносить его в волшебный журнал, поставьте оператор Log & operator << (ostream & (* f) (ostream &)) { cout << * f; return * this; }. –

+0

@Earwicker. Спасибо за хорошее решение. Пожалуйста, объясните, что значит создавать экземпляр класса без создания объектной переменной. Я новичок в C++ и никогда не видел этого раньше. – jackhab

-1

Вы могли бы также override the operator. Это позволит вам вызывать другую функцию или префикс/суффикс что-либо, что оставит выходной буфер с тем, что вы пожелаете: в вашем случае вы должны вывести определенную строку.

+0

-1.При переопределении оператора создается верхний и нижний колонтитулы для каждого элемента, отформатированного: например. "new_cout << 1 << 2 << 3;" будет создавать 3 верхних и нижних колонтитула. –

+0

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

0

Вам необходимо переопределить оператора < <(), но вы даже не должны подкласса std :: cout. Вы также можете создать новый объект или использовать существующие объекты, подобные этому.

1

Далее от ответа Мыкола, я имею следующую реализацию в моем коде. Использование является

  LOG_DEBUG("print 3 " << 3); 

печатает

  DEBUG (f.cpp, 101): print 3 3 

Вы можете изменить его, чтобы использовать FUNCTION вдоль/вместо ЛИНИИ и ФАЙЛ

/// Implements a simple logging facility. 
class Logger 
{ 
     std::ostringstream os_; 
     static Logger* instance_; 
     Logger(); 
public: 
     static Logger* getLogger(); 
     bool isDebugEnabled() const; 
     void log(LogLevelEnum l, std::ostringstream& os, const char* filename, int lineno) const; 
     std::ostringstream& getStream() 
     { return os_; } 
}; 

void Logger::log(LogLevelEnum l, std::ostringstream& os, const char* filename, int lineno) const 
{ 
     std::cout << logLevelEnumToString(l) << "\t(" << fileName << ": " << lineno << ")\t- " << os.str(); 
     os.str(""); 
} 

#define LOG_common(level, cptext) do {\ 
     utility::Logger::getLogger()->getStream() << cptext; \ 
     utility::Logger::getLogger()->log(utility::level, utility::Logger::getLogger()->getStream(), __FILE__, __LINE__); \ 
} while(0); 

enum LogLevelEnum { 
     DEBUG_LOG_LEVEL, 
     INFO_LOG_LEVEL, 
     WARN_LOG_LEVEL, 
     ERROR_LOG_LEVEL, 
     NOTICE_LOG_LEVEL, 
     FATAL_LOG_LEVEL 
}; 

#define LOG_DEBUG(cptext) LOG_common(DEBUG_LOG_LEVEL, cptext) 
#define LOG_INFO(cptext)  LOG_common(INFO_LOG_LEVEL , cptext) 
#define LOG_WARN(cptext)  LOG_common(WARN_LOG_LEVEL , cptext) 
#define LOG_ERROR(cptext) LOG_common(ERROR_LOG_LEVEL, cptext) 
#define LOG_NOTICE(cptext) LOG_common(NOTICE_LOG_LEVEL, cptext) 
#define LOG_FATAL(cptext) LOG_common(FATAL_LOG_LEVEL, cptext) 

const char* logLevelEnumToString(LogLevelEnum m) 
{ 
     switch(m) 
     { 
       case DEBUG_LOG_LEVEL: 
         return "DEBUG"; 
       case INFO_LOG_LEVEL: 
         return "INFO"; 
       case WARN_LOG_LEVEL: 
         return "WARN"; 
       case NOTICE_LOG_LEVEL: 
         return "NOTICE"; 
       case ERROR_LOG_LEVEL: 
         return "ERROR"; 
       case FATAL_LOG_LEVEL: 
         return "FATAL"; 
       default: 
         CP_MSG_ASSERT(false, CP_TEXT("invalid value of LogLevelEnum")); 
         return 0; 
     } 
} 
2
#define debug_print(message) (std::cout << __FUNCTION__ << (message) << std::endl) 

Это имеет то преимущество, что вы можете отключить все отладочные сообщения на один раз, когда вы сделали

#define debug_print(message)() 
0

Для целей лесозаготовительной я использую что-то вроде

#define LOG(x) \ 
    cout << __FUNCTION__ << x << endl 

// ... 
LOG("My message with number " << number << " and some more"); 

Проблемы с вашим подходом является (как Микола Golybyew пояснил), что ФУНКЦИЯ обрабатывается во время компиляции и поэтому всегда печатает одно и то же имя с помощью не препроцессорного решения.

Если это только для добавления Endl ваших сообщений, вы можете попробовать что-то вроде:

class MyLine { 
public: 
    bool written; 
    std::ostream& stream; 
    MyLine(const MyLine& _line) : stream(_line.stream), written(false) { } 
    MyLine(std::ostream& _stream) : stream(_stream), written(false) { } 
    ~MyLine() { if (!written) stream << "End of Message" << std::endl; } 
}; 

template <class T> MyLine operator<<(MyLine& line, const T& _val) { 
    line.stream << _val; 
    line.written = true; 
    return line; 
} 

class MyStream { 
public: 
    std::ostream& parentStream; 
    MyStream(std::ostream& _parentStream) : parentStream(_parentStream) { } 
    MyLine getLine() { return MyLine(parentStream); } 
}; 

template <class T> MyLine operator<<(MyStream& stream, const T& _val) { 
    return (stream.getLine() << _val); 
} 

int main() 
{ 
     MyStream stream(std::cout); 
     stream << "Hello " << 13 << " some more data"; 
     stream << "This is in the next line " << " 1 "; 
    return 0; 
} 

Обратите внимание, что это важно не возвращать ссылки из функций оператора. Поскольку MyLine должен существовать только как временный (поскольку его деструктор запускает запись endl), первый объект (возвращаемый функцией getLine() в MyStream) будет разрушен до вызова второго operator<<. Поэтому объект MyLine копируется в каждом operator<<, создавая новый. Последний объект разрушается без написания и называет конец сообщения в своем деструкторе.

Просто попробуйте в отладчике, чтобы понять, что происходит ...

Смежные вопросы