2014-11-06 13 views
10

Giả sử tôi có một hàm có tham số ostream &o và ghi vào luồng đó. Việc thực hiện operator << sẽ là một ví dụ tốt.Tôi có nên tạo một đoạn phim tạm thời bằng cách sử dụng streambuf của người khác không?

ostream& operator << (ostream& o, const MyThing& t) 
{ 
    // ... interesting code here ... 
    return o; 
} 

Trong hàm, tôi có thể muốn chỉ định tùy chọn định dạng trên luồng. Ví dụ, tôi có thể muốn một số được in dưới dạng hex, bất kể cách o được định cấu hình khi nó được truyền vào hàm.

Thứ hai, tôi có thể muốn có thể đưa ra các giả định về các cờ định dạng hiện tại. Ví dụ, nó sẽ là tốt đẹp để có thể giả định rằng các con số đã được định dạng như số thập phân, trừ khi tôi yêu cầu khác.

Cuối cùng, khi chức năng thoát tôi muốn các tùy chọn định dạng trên o giống như trước khi hàm được gọi, để xuất hiện không thay đổi đối với người gọi. Đây chỉ đơn giản là vấn đề lịch sự với người gọi. Cho đến bây giờ tôi đã đạt được điều này bằng cách tạo ra một địa phương ostringstream trong chức năng, làm tất cả công việc của tôi trên đó (bao gồm các tùy chọn định dạng cài đặt), và gửi .str() đến o ở cuối hàm. Câu hỏi StackOverflow here cho thấy rằng những người thông minh hơn tôi có cùng một cách tiếp cận. Tuy nhiên, nó làm phiền tôi rằng tôi đang giữ rất nhiều dữ liệu trong ostringstreams có lẽ có thể được gửi đến đầu ra trước đó (các chuỗi có thể nhận được khá lớn).

Tôi có hai câu hỏi:

1) Có quy phạm pháp luật, thành ngữ, hình thức tốt, , vv để tạo ra một tạm thời ngăn xếp dựa) ostream (khoảng o.rdbuf() và làm công việc của tôi trên ostream đó? Các thử nghiệm của riêng tôi và trang tại cppreference.com dường như gợi ý rằng tôi có thể.

ostream& operator << (ostream& o_, const MyThing& t) 
{ 
    ostream o (o_.rdbuf()); 
    // write stuff to "o", 
    // setting formatting options as I go. 
    return o_; // Formatting on the parameter ostream o_ unchanged. 
} 

2) Có cách nào khác, tốt hơn tôi chưa xem xét?

Trả lời

0

Cài đặt có thể được lưu trữ trong một loại đối tượng được gọi là đối tượng fmtflags, được định nghĩa trong một lớp có tên là ios, được bao gồm trong iostream. Bạn có thể khai báo một trong số các đối tượng này, nhưng bạn phải khai báo nó bằng toán tử phân giải phạm vi.

Tuyên bố sau đây sẽ tiết kiệm một số khía cạnh của tình trạng định dạng trong old_settings biến:

ios::fmtflags old_settings = cout.flags(); 

Sau đó, sau khi làm sản lượng sử dụng cài đặt mới, bạn có thể khôi phục các thiết lập cũ bằng cách gọi hàm tương tự với cài đặt cũ làm đối số:

cout.flags(old_settings); 

Các cài đặt khác có thể lấy và khôi phục bằng chức năng thành viên. Ví dụ:

int old_precision = cout.precision(); 

sẽ lưu đặc điểm kỹ thuật chính xác hiện tại.Sau đó

cout.precision(old_precision); 

sẽ khôi phục lại độ chính xác giá trị ban đầu

+0

Những cuộc gọi tốt nhất sẽ được đặt trong constructor và destructor của một số đối tượng dựa trên stack. Tôi cho rằng đó là những gì các lớp Boost làm. – peterpi

1

Đó không phải là giải pháp tồi; nó chắc chắn là hợp pháp. Tôi không nghĩ rằng quá phổ biến, do đó, có thể là một ý tưởng hay để nhận xét là lý do bạn thực hiện điều đó.

Các giải pháp thường xuyên nhất mà tôi đã nhìn thấy ở đây là để tạo ra một lớp bảo vệ nhà nước , mà sẽ lưu tất cả các trạng thái bạn cần (thông thường, flags(), precision()fill()) trong constructor , và khôi phục lại nó trong destructor, và sau đó để buộc phải đặt tất cả các tùy chọn bạn muốn. (Có thể sử dụng copyfmt cho điều này, mặc dù điều này cũng có bản sao thứ như mặt nạ ngoại lệ, mà có thể bạn không muốn chơi với.)

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