2009-03-23 34 views
10

Làm thế nào tôi có thể lấy được một lớp từ cout do đó, ví dụ, bằng văn bản cho nótùy chỉnh cout

new_cout << "message";

sẽ tương đương với

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

Trả lời

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__) 

Do đó:

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

+1. Không giống như tất cả các câu trả lời chỉ nói "ghi đè toán tử <<()", giải pháp này giải quyết thực tế rằng đầu trang và chân trang cần được xuất một lần trên mỗi câu lệnh, không phải một lần cho mỗi <<. –

+0

+1 thực sự, ý tưởng hay. chỉ cần một cái gì đó về endl: tôi nghi ngờ cho một thông báo gỡ lỗi, endl là hiếm khi cần thiết, nhưng nếu bạn muốn để có thể << nó vào nhật ký ma thuật quá, đặt một Log & operator << (ostream & (* f) (ostream &)) { cout << * f; return * this; }. –

+0

@Earwicker. Cảm ơn vì giải pháp tốt đẹp của bạn. Vui lòng giải thích ý nghĩa của việc tạo một lớp mà không tạo biến đối tượng. Tôi mới đến với C++ và chưa bao giờ thấy điều này trước đây. – jackhab

-1

Bạn cũng có thể override the operator. Nó sẽ cho phép bạn gọi một hàm khác hoặc tiền tố/hậu tố bất cứ điều gì sẽ rời khỏi bộ đệm đầu ra với bất cứ điều gì bạn muốn: Trong trường hợp của bạn, bạn sẽ có nó xuất ra một chuỗi cụ thể.

+0

-1.Việc ghi đè toán tử sẽ tạo đầu trang và chân trang cho mỗi mục được định dạng: ví dụ: "new_cout << 1 << 2 << 3;" sẽ tạo 3 đầu trang và chân trang. –

+0

Có, đề xuất của tôi giả định người viết ghi đè để biết vị trí cần thực hiện, đối với loại nào và mã của anh ấy thực sự sẽ sử dụng đúng cách. –

0

Bạn phải ghi đè toán tử < <(), nhưng bạn thậm chí không phải phân lớp std :: cout. Bạn cũng có thể tạo một đối tượng mới hoặc sử dụng các đối tượng hiện có như thế.

1

Tiếp tục từ phản ứng Mykola, tôi có thực hiện sau trong mã của tôi. Việc sử dụng là

  LOG_DEBUG("print 3 " << 3); 

in

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

Bạn có thể sửa đổi nó để sử dụng CHỨC NĂNG cùng/thay ĐƯỜNG DÂYFILE

/// 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) 

này có lợi thế mà bạn có thể vô hiệu hóa tất cả các thư debug cùng một lúc khi bạn đã hoàn tất

#define debug_print(message)() 
0

Đối với mục đích khai thác gỗ tôi sử dụng một cái gì đó giống như

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

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

Vấn đề với cách tiếp cận của bạn là (như Mykola Golybyew giải thích) rằng FUNCTION được xử lý tại thời gian biên dịch và do đó sẽ luôn luôn in cùng tên với một giải pháp không tiền xử lý.

Nếu nó chỉ cho thêm endl đến tin nhắn của bạn, bạn có thể thử một cái gì đó như:

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

Note, mà điều quan trọng là không trở lại tài liệu tham khảo từ các chức năng điều hành. Vì MyLine chỉ nên tồn tại như một tạm thời (cho destructor của nó gây ra các văn bản của endl), đối tượng đầu tiên (trả về bởi các chức năng getLine() trong MyStream) sẽ bị hủy trước khi thứ hai operator<< được gọi. Do đó đối tượng MyLine được sao chép trong mỗi operator<< tạo đối tượng mới. Đối tượng cuối cùng bị hủy bỏ mà không được ghi vào và ghi kết thúc của thông báo trong destructor của nó.

Chỉ cần dùng thử trong trình gỡ lỗi để hiểu điều gì đang xảy ra ...