2013-02-02 34 views
8

Giả sử chúng ta có nhiều cấp độ ghi nhật ký: theo dõi, gỡ lỗi, thông tin, lỗi. Tôi đã tự hỏi nếu có một cách để viết các đoạn mã sau:Đăng nhập lơ lửng trong C++

enum log_level = {trace, debug, info, error}; 

log_level global_log_level = info; 

void log(log_level level, string& message){ 
    if (level >= global_log_level){ 
     std::cout << message << std::endl; 
    } 
} 

string create_message(){ 
    ... 
} 

log_level level = debug; 
log (level, create_message()); 

mà không create_message được gọi nếu mức nhỏ global_severity_level đó. Thật vậy, create_message có thể khá dài, và không có vấn đề gì nó tạo ra một chuỗi. Nếu có nhiều nhật ký "gỡ lỗi", những nhật ký đó có thể trở thành chi phí đáng kể khi chạy ở chế độ không gỡ lỗi.

Tôi biết có thể làm như vậy nếu hàm "nhật ký" là macro, gọi hàm create_message() chỉ khi mức độ nghiêm trọng> minimal_severity; nhưng không có cách nào khác để làm điều này nếu không có macro?

EDIT

Ở phía trên, tôi không nói rõ create_message, bởi vì nó có thể là bất cứ điều gì, cụ thể:

log(level, "Created object " + my_object.getName()); 

Trong trường hợp này, là có một cách để viết log như vậy rằng chuỗi đầy đủ không được tạo ra, theo cách tương đối minh bạch cho nhật ký gọi lập trình viên?

Rất cám ơn

+0

Bạn có thể có 'create_message()' kiểm tra 'global_log_level'. – NPE

+0

Bạn có thể chuyển một hàm 'create_message' vào' log() 'vì vậy' log() 'sẽ chỉ xây dựng thông điệp đắt tiền nếu mức thích hợp? – JaredC

+0

Xin chào, tôi tham khảo một hàm không xác định create_message() vì thông báo có thể đến từ bất kỳ đâu, nhưng nó có thể được viết khi đang bay, như nhật ký (cấp độ, "Đối tượng" + my_object.getName() + "đã được tạo") ; - trong trường hợp này tôi không thể chuyển bất kỳ thứ gì tới hàm create_message(), mà về cơ bản là toán tử + giữa 2 chuỗi ... Và tôi không thể chuyển nó thành hàm log ... – GHL

Trả lời

5

Tương tự như @ftftbit, nhưng theo đề xuất của @ipc.

Sử dụng mẫu để tránh tiêu chuẩn :: máy móc chức năng và trình biên dịch có thể nội tuyến và do đó hy vọng sẽ kết thúc nhanh hơn.

template< typename F > 
void log(log_level level, F message_creator){ 
    if (level >= global_log_level){ 
     std::cout << message_creator() << std::endl; 
    } 
} 
+0

+1 bởi vì tôi không có thời gian để thay đổi câu trả lời của mình: D –

+0

+1 bởi vì tôi không nghĩ ra câu trả lời của riêng mình : D – ipc

+0

Cảm ơn các ý tưởng và +1. :) –

6

Có một số lựa chọn thay thế. Một trong những thú vị là để vượt qua create_message như một std::function<std::string()> và gọi nó từ bên trong log:

void log(log_level level, std::function<std::string()> message_creator){ 
    if (level >= global_log_level){ 
     std::cout << message_creator() << std::endl; 
    } 
} 

Sau đó, bạn sẽ gọi nó là như vậy:

log(level, create_message); 

này có thể làm việc với các biểu thức tùy ý như các đối số nếu bạn quấn chúng trong một lambda:

log(level, [&](){ return "Created object " + my_object.getName(); }); 

Nếu bạn thực sự không muốn đối số được đánh giá cả (như bạn đã mô tả trong dấu phẩy ts), sau đó bạn sẽ cần phải kiểm tra mức độ bên ngoài của cuộc gọi:

if (level >= global_log_level) { 
    log(level, create_message()); 
} 
+0

Thay thế '[]' bằng '[&]'. Ngoài ra những gì nếu create_message là bất kỳ chức năng tùy ý lấy một số đối số? Có vẻ như không đủ để trì hoãn chức năng tạo thông báo; nó cũng có vẻ hợp lý để trì hoãn việc đánh giá các đối số của hàm. Làm thế nào 'log' chức năng sẽ biết về những đối số là một vấn đề khác. – Nawaz

+3

Làm cho 'log' một mẫu, sau đó trình biên dịch sẽ có thể inline lambda. – ipc

+0

@Nawaz: trong trường hợp này, bạn kết thúc cuộc gọi vào một lambda không tham số. – ybungalobill

1

@sftrabbit câu trả lời được ưa thích. Nhưng chỉ nếu bạn không muốn thay đổi log(), bạn có thể gọi nó là:

log (level, (level >= global_log_level)? create_message() : ""); 
+0

Thật vậy, công trình này, không nghĩ về toán tử bậc ba ... Nhưng nếu người gọi nhật ký không nhận thức được nội bộ của trình ghi nhật ký và sự tồn tại của biến global_log_level thì sao? – GHL

+0

@GHL Sau đó, bạn biến cấu trúc này thành macro. Vâng, thông số, eh ;-) – paddy

+0

Có thực sự, nhưng sẽ làm :) – GHL

1

Bạn có thể tạo một macro



    #define log(level, message) { \ 
    if(level >= global_log_level) {\ 
    cout << message; }} 

Bây giờ nếu bạn gọi

log(debug, create_message());
create_message sẽ được gọi là chỉ khi mức độ debug là mong muốn.

+1

Cảm ơn, nhưng vấn đề là tìm một giải pháp thay thế để tạo nhật ký macro ... – GHL

+0

Chỉ cần tò mò, tại sao macro là tùy chọn tồi cho bạn? – strannik

+1

Theo tôi, đây là giải pháp tốt nhất trước C++ 11. – ipc

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