2010-08-16 29 views
5

Tôi đang viết một lớp bản ghi trong C++. Lớp này là một singleton. Tôi muốn thêm các bản ghi theo cách như vậy:toán tử << - cách phát hiện đối số cuối cùng

Log::GetInstance() << "Error: " << err_code << ", in class foo"; 

Ok, và bên trong một đối tượng Log, tôi muốn lưu toàn bộ dòng này vào thời điểm đó khi tranh luận cuối cùng đến ("trong lớp foo" trong ví dụ này).

Cách phát hiện đối số cuối cùng < <? a < < b < < is_this_last < < maybe_this_is < < or_not.

Tôi không sử dụng bất kỳ thẻ kết thúc nào.

+1

Tôi không nghĩ rằng toán tử quá tải << là điều bạn muốn ở đây – Falmarri

+1

@Falmarri: Tôi thực sự rất thích cách tiếp cận này. Đó là cách Qt sử dụng lớp 'QDebug' của nó. – Job

+1

Và QT đang làm việc chống lại ngôn ngữ. Chỉ vì họ không thể có nghĩa là họ nên. –

Trả lời

17

Bạn có thể giải quyết vấn đề này bằng cách không sử dụng singleton. Nếu bạn thực hiện một chức năng như thế này:

Log log() 
{ 
    return Log(); 
} 

Bạn có thể thêm một khúc gỗ gần giống như cách bạn đã làm trước đó:

log() << "Error: " << err_code << ", in class foo"; 

Sự khác biệt được rằng destructor của đối tượng Log được gọi sau khi dòng này . Vì vậy, bây giờ bạn có một cách để phát hiện khi đối số cuối cùng đã được xử lý.

+0

Một số đối tượng ở đâu đó vẫn phải duy trì xử lý tệp đang mở… – Potatoswatter

+0

@Potatoswatter: Có. Vì anh ta đang sử dụng một singleton, tôi muốn nói nó là một thành viên tĩnh của lớp 'Log'. Các giải pháp khác là tất nhiên có thể. – Job

+0

Tôi thích kỹ thuật RAII chơi với hàm tạo và phá hủy, tôi nghĩ nó thực sự tao nhã. –

9

Tôi sẽ trả lại đối tượng proxy thay vì đối tượng nhật ký. Đối tượng proxy sẽ lưu dữ liệu được ghi vào nó, và sau đó trong destructor của nó, nó sẽ thực sự ghi dữ liệu được tích lũy vào nhật ký.

+0

+1: Mặc dù người độc thân có thể xấu xí, tốt hơn là đưa ra lời khuyên yêu cầu tái cấu trúc không cần thiết ít hơn. – Potatoswatter

1

Đừng quá thông minh với nhà điều hành của bạn. Bạn nên quá tải các nhà khai thác khi nó làm cho tinh thần để làm như vậy. Ở đây bạn không nên. Điều đó có vẻ lạ.

Bạn chỉ cần có một phương pháp tĩnh trông như thế này:

Log::Message(message_here); 

mà phải mất một std :: string. Sau đó, khách hàng có đầu-ache của figuring ra làm thế nào để lắp ráp các chuỗi lỗi.

+4

Tại sao nó lạ? Các luồng C++ hoạt động chính xác theo cùng một cách. – Job

+0

@Job: Không, luồng C++ thì không. Cụ thể, họ không làm gì đặc biệt trong lời kêu gọi cuối cùng. Một đối tượng dòng C++ sử dụng 'toán tử <<()' để chạy một hàm của một đối số, và trả về một đối tượng dòng C++ có thể chạy lại một hàm. Vận hành quá tải là gọn gàng, nhưng nó không phải là rất linh hoạt hoặc mở rộng, và có những trường hợp, nơi thêm một yêu cầu khác làm cho nhà điều hành quá tải một ý tưởng xấu. –

+0

@ David: Nhưng câu trả lời không phải là nói về toán tử << 'nào, điều đó chỉ làm' toán tử << 'ở nơi đầu tiên là lạ. Mà nó không phải là. – GManNickG

4

Bạn đặt nhật ký trả về một đối tượng khác sau toán tử < <.

template<typename T> 
LogFindT operator<<(Log aLog, T const& data) 
{ 
    // Put stuff in log. 
    log.putStuffInLog(data); 

    // now return the object to detect the end of the statement. 
    return LogFindT(aLog); 
} 


struct LogFindT 
{ 
    LogFindT(Log& aLog) : TheLog(aLog) {} 
    Log& TheLog; 
    ~LogFindT() 
    { 
     // Do stuff when this object is eventually destroyed 
     // at the end of the expression. 
    } 
}; 

template<typename T> 
LogFindT& operator<<(LogFindT& aLog, T const& data) 
{ 
    aLog.TheLog.putStuffInLog(data); 

    // Return a reference to the input so we can chain. 
    // The object is thus not destroyed until the end of the stream. 
    return aLog; 
} 
4

Tôi nghĩ rằng Jerry và Martin đã đưa ra những gợi ý tốt nhất, nhưng vì lợi ích của sự hoàn chỉnh, điều đầu tiên tôi nghĩ đến là std::endl.

Nếu bạn thực hiện Log trong hệ thống iostream bởi một lớp tùy chỉnh streambuf, sau đó bạn chỉ có thể thêm << endl hoặc << flush vào cuối dòng. Vì bạn đang hỏi, tôi cho rằng bạn đã không làm vậy.

Nhưng bạn có thể bắt chước cách hoạt động của endl.Hoặc là thêm một handler thao túng

Log &operator<< (Log &l, Log & (*manip)(Log &)) 
    { return manip(l); } // generically call any manipulator 

Log &flog(Log &l) // define a manipulator "flush log" 
    { l->flush(); return l; } 

hoặc thêm một chuyên operator<<

struct Flog {} flog; 

Log &operator<< (Log &l, Flog) 
    { l->flush(); return l; } 
0

Không có cách nào tốt để làm những gì bạn muốn. C và C++ đơn giản không phải là ngôn ngữ hướng dòng. Không có đơn vị lớn hơn như một "dòng mã" hoặc bất cứ điều gì, cũng không phải là chuỗi cuộc gọi kết hợp trong bất kỳ cách nào.

Trong C++ khái niệm "một < < b < < c < < d" là chính xác tương đương với ba cuộc gọi riêng biệt để điều hành < <, như thế này:

t1 = a; 
t2 = t1.operator<<(b); 
t3 = t2.operator<<(c); 
t4 = t3.operator<<(d); 

Đó là lý do tại sao C++ ostreams sử dụng endl như một dấu đầu dòng rõ ràng; không có cách nào tốt để làm điều đó bằng cách khác.

+0

BTW, tôi đánh giá cao tất cả các câu trả lời khác mà đã đưa ra cách để làm điều đó. Tạo thời gian sống tạm thời và proxy và như vậy là một sự chuyển hướng học tập thú vị, nhưng trong thực tế nó sẽ tạo ra chi phí thời gian chạy thêm và làm phức tạp việc gỡ lỗi (của hệ thống đăng nhập và gỡ lỗi của bạn!) nếu có gì sai. Tôi không thực sự muốn đến đó, bởi vì nếu bạn không hiểu nó đủ tốt để tự nghĩ ra, đó chỉ là một cách phức tạp hơn để tự bắn mình vào chân. Vì vậy, tôi vẫn chịu sự khẳng định của tôi - không có cách nào tốt để làm những gì bạn muốn. :-) –

+2

Vì vậy, về cơ bản thay vì dạy họ bạn nói "bạn không thể hình dung ra, đừng thử."? Ngoài ra, các proxy này sẽ được biên dịch hoàn toàn bởi bất kỳ trình biên dịch nào được thực hiện trong thập kỷ qua, không có phí. Ngay cả khi có, một giao diện sạch sẽ tốt hơn một giao diện nhanh. (Người ta luôn có thể làm cho một giao diện sạch sẽ nhanh chóng * với một hồ sơ * (không đoán), nhưng một giao diện nhanh chóng là khó khăn hơn nhiều để làm sạch.) – GManNickG

+1

Tôi không đồng ý (với Drew). Tạo thời gian không phải là một thực hành học tập nhưng nhìn thấy khá thường xuyên trong mã thương mại. Không có chi phí đáng kể (một trong những tin đồn trên Internet) và nó không phải là khó để gỡ lỗi (vì nó là tương đối dễ dàng để có được viết lần đầu tiên (vì vậy không có lỗi)). –

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