2010-02-01 36 views
14

Tôi đang cố gắng để thực hiện riêng QDebug() phong cách dòng debug-đầu ra của tôi, điều này về cơ bản là những gì tôi có cho đến nay:QDebug() << stuff; thêm một dòng mới tự động?

struct debug 
{ 
#if defined(DEBUG) 
    template<typename T> 
    std::ostream& operator<<(T const& a) const 
    { 
     std::cout << a; 
     return std::cout; 
    } 
#else 
    template<typename T> 
    debug const& operator<<(T const&) const 
    { 
     return *this; 
    } 

    /* must handle manipulators (endl) separately: 
    * manipulators are functions that take a stream& as argument and return a 
    * stream& 
    */ 
    debug const& operator<<(std::ostream& (*manip)(std::ostream&)) const 
    { 
     // do nothing with the manipulator 
     return *this; 
    } 
#endif 
}; 

sử dụng tiêu biểu:

debug() << "stuff" << "more stuff" << std::endl; 

Nhưng tôi muốn không phải thêm std :: endl;

Câu hỏi của tôi là về cơ bản, làm thế nào tôi có thể nói khi kiểu trả về của nhà điều hành < < sẽ không được sử dụng bởi nhà điều hành khác < < (và do đó thêm endl)? Cách duy nhất tôi có thể nghĩ đến để đạt được bất kỳ thứ gì như thế này là tạo danh sách các thứ cần in với liên kết với từng đối tượng tạm thời được tạo bởi debug(), sau đó in mọi thứ, cùng với dấu mới (và I có thể làm những thứ thông minh như chèn dấu cách) trong ~ debug(), nhưng rõ ràng đây không phải là lý tưởng vì tôi không đảm bảo rằng đối tượng tạm thời sẽ bị hủy cho đến khi kết thúc phạm vi (hay tôi?).

+4

'qDebug()' chỉ tạo đối tượng tạm thời. Thực hiện theo các biểu tượng và bạn sẽ tìm thấy một cái gì đó như thế này: 'QDebug qDebug() {return QDebug (QtDebugMsg); } '. –

Trả lời

8

Qt sử dụng một phương pháp tương tự như @ Evan.Xem a version of qdebug.h để biết chi tiết triển khai, nhưng chúng truyền tất cả mọi thứ đến luồng văn bản cơ bản, sau đó tuôn ra luồng và dòng cuối hủy tiêu chuẩn QDebug tạm thời được trả về bởi qDebug().

+0

Cảm ơn, đó là những gì tôi tự hỏi, và xác nhận rằng tạm thời bị hủy vĩnh viễn hầu hết thời gian :) – James

+1

@Autopulated: Tôi quên chính xác verbiage, nhưng tôi tin rằng các tiêu chuẩn bắt buộc rằng một đối tượng vô danh bị phá hủy ngay lập tức sau khi biểu hiện nó được tạo ra. –

+2

Aha! tìm thấy nó: 12.2/4 nói "Có hai bối cảnh trong đó thời gian bị phá hủy tại một điểm khác với kết thúc của biểu thức đầy đủ." Về cơ bản có nghĩa là ngoài hai trường hợp ngoại lệ sắp được liệt kê, các đối tượng tạm thời sẽ bị hủy ngay lập tức ở cuối biểu thức. –

0

Chèn luồng (<<) và trích xuất (>>) được cho là không phải là thành viên.

Câu hỏi của tôi là về cơ bản, làm thế nào tôi có thể biết khi nào các kiểu trả về của hành < < sẽ không được sử dụng bởi điều hành khác < < (và do đó thêm endl)?

Bạn không thể. Tạo một hàm thành viên để đặc biệt nối thêm hoặc thêm một số endl sau khi thực hiện các cuộc gọi kết nối đó. Ghi lại lớp học của bạn tốt để khách hàng biết cách sử dụng nó. Đó là đặt cược tốt nhất của bạn.

+0

Tôi sẽ là người dùng chính của việc này; Tôi đang cố gắng để tiết kiệm bằng văn bản std :: endl hơn và hơn và hơn nữa. – James

+0

'endl' thực hiện hai thứ - 1) thêm một dòng mới - đó là thứ bạn không thể kiểm soát vì chuỗi có thể có dòng mới được nhúng và 2) xóa luồng đầu ra - mà bạn có thể kiểm soát mà không cần đặt chúng trong dtor. Câu hỏi của bạn không rõ ràng những gì bạn đang cố gắng đạt được. – dirkgently

5

Khi bạn viết rằng đây là việc sử dụng điển hình:

debug() << "stuff" << "more stuff" << std::endl; 

được bạn chắc chắn có kế hoạch xây dựng một đối tượng debug mỗi khi bạn sử dụng nó? Nếu vậy, bạn sẽ có thể để có được hành vi mà bạn muốn bằng cách có debug destructor thêm xuống dòng:

~debug() 
{ 
    *this << std::endl; 

    ... the rest of your destructor ... 
} 

Điều đó không có nghĩa là bạn không thể làm một cái gì đó như thế này:

// this won't output "line1" and "line2" on separate lines 
debug d; 
d << "line1"; 
d << "line2"; 
+0

@last part: Sẽ hoạt động nếu bạn bao quanh nó với niềng răng. Khi đối tượng gỡ lỗi nằm ngoài phạm vi, hàm hủy của nó được gọi. – jmucchiello

+0

@jmucchiello: Hàm hủy sẽ được gọi ở cuối câu lệnh, chính xác là khi bạn muốn chèn dòng mới. – Ben

+0

@jmucchiello - ý tôi là "không hoạt động" là line1 và line2 sẽ không nằm trên các dòng riêng biệt giống như chúng đã viết nếu bạn đã viết 'debug() <<" line1 "; debug() << "line2()"; ' –

15

Cái gì đó như điều này sẽ làm:

struct debug { 
    debug() { 
    } 

    ~debug() { 
     std::cerr << m_SS.str() << std::endl; 
    } 

public: 
    // accepts just about anything 
    template<class T> 
    debug &operator<<(const T &x) { 
     m_SS << x; 
     return *this; 
    } 
private: 
    std::ostringstream m_SS; 
}; 

nào nên cho phép bạn làm những việc như thế này:

debug() << "hello world"; 

Tôi đã sử dụng một mẫu như thế này kết hợp với một khóa để cung cấp một luồng giống như hệ thống ghi nhật ký có thể đảm bảo rằng các mục nhập nhật ký được viết một cách nguyên tử.

LƯU Ý: Mã chưa được kiểm tra, nhưng nên làm việc :-)

+0

Bạn có một sai lầm: destructor nên được gọi là "gỡ lỗi". Ngoài ra, tại sao sử dụng ostringstream trung gian? Bạn không thể chỉ cần đầu ra những thứ để cerr khi họ đến nhà điều hành của bạn < Manuel

+3

Tôi đã sửa tên hủy (lỗi sao chép/dán). nhưng chuỗi có một mục đích. Nó làm cho nó như vậy đầu ra không được viết ra cho đến khi destructor được gọi là (làm cho nó có thể ngăn chặn vấn đề luồng). –

Các vấn đề liên quan