2012-12-12 47 views
9

Tôi gặp sự cố khi cố triển khai lớp luồng tùy chỉnh để tạo mã thụt lề độc đáo trong tệp đầu ra. Tôi đã tìm kiếm trực tuyến rộng rãi nhưng dường như không có sự đồng thuận về cách tốt nhất để đạt được điều này. Một số người nói về bắt nguồn suối, những người khác nói về việc suy luận ra đệm, tuy nhiên những người khác đề nghị việc sử dụng các miền địa phương/khía cạnh, vvC++ luồng đầu ra tùy chỉnh với thụt đầu dòng

Về cơ bản, tôi thấy bản thân mình viết rất nhiều mã như thế này:

ofstream myFile(); 
myFile.open("test.php"); 
myFile << "<html>" << endl << 
      "\t<head>" << endl << 
      "\t\t<title>Hello world</title>" << endl << 
      "\t</head>" << endl << 
      "</html>" << endl; 

Khi các tab bắt đầu để thêm lên có vẻ khủng khiếp, và nó có vẻ như nó sẽ được tốt đẹp để có một cái gì đó như thế này:

ind_ofstream myFile(); 
myFile.open("test.php"); 
myFile << "<html>" << ind_inc << ind_endl << 
      "<head>" << ind_inc << ind_endl << 
      "<title>Hello world</title>" << ind_dec << ind_endl << 
      "</head>" << ind_dec << ind_endl << 
      "</html>" << ind_endl; 

tức là tạo ra một lớp dòng có nguồn gốc mà sẽ theo dõi độ sâu thụt như hiện nay, sau đó một số thao tác để tăng/giảm thụt lề chiều sâu, và một người thao túng để viết một dòng mới theo sau bởi nhiều tab.

Vì vậy, đây là bắn tôi tại thực hiện các lớp & thao tác:

ind_ofstream.h

class ind_ofstream : public ofstream 
{ 
    public: 
     ind_ofstream(); 
     void incInd(); 
     void decInd(); 
     size_t getInd(); 

    private: 
     size_t _ind; 
}; 

ind_ofstream& inc_ind(ind_ofstream& is); 
ind_ofstream& dec_ind(ind_ofstream& is); 
ind_ofstream& endl_ind(ind_ofstream& is); 

ind_ofstream.cpp

ind_ofstream::ind_ofstream() : ofstream() {_ind = 0;} 
void ind_ofstream::incInd()  {_ind++;} 
void ind_ofstream::decInd()  {if(_ind > 0) _ind--;} 
size_t ind_ofstream::getInd()  {return _ind;} 

ind_ofstream& inc_ind(ind_ofstream& is)  
{ 
    is.incInd(); 
    return is; 
} 

ind_ofstream& dec_ind(ind_ofstream& is)  
{ 
    is.decInd(); 
    return is; 
} 

ind_ofstream& endl_ind(ind_ofstream& is)  
{ 
    size_t i = is.getInd(); 
    is << endl; 
    while(i-- > 0) is << "\t"; 
    return is; 
} 

này được xây dựng, nhưng không tạo ra kết quả mong muốn ; bất kỳ nỗ lực nào để sử dụng các trình điều khiển tùy chỉnh dẫn đến việc chúng được truyền tới một boolean vì một lý do nào đó và "1" được ghi vào tệp. Tôi có cần quá tải toán tử < < cho lớp mới của mình không? (Tôi đã không thể tìm thấy cách để làm điều này mà xây dựng)

Cảm ơn!

p.s.

1) Tôi đã bỏ qua #includes, sử dụng không gian tên vv từ đoạn mã của tôi để tiết kiệm dung lượng.

2) Tôi đang hướng đến việc có thể sử dụng giao diện tương tự như giao diện trong đoạn mã thứ hai của mình. Nếu sau khi đọc toàn bộ bài đăng, bạn nghĩ đó là một ý tưởng tồi, vui lòng giải thích lý do và cung cấp giải pháp thay thế.

+1

Câu hỏi: nếu kết quả mong muốn là mã sạch và đầu ra chính xác - nghĩa là, nếu đây không chỉ là học thuật hoặc cho sự cải thiện của bạn - tại sao viết [HT | X] ML trực tiếp theo cách này? Ít nhất, bạn có thể viết nó vào đĩa Unindented, sau đó sử dụng một số prettifier (gọn gàng, ví dụ) để làm công việc bẩn thỉu này. ... điều đó đang được nói, điều đó thật thú vị, và tôi có một cảm giác béo bở, tôi sẽ sớm kết hợp một giải pháp với nhau. :) – Christopher

+0

Xin chào - đó là một ý tưởng hay và có lẽ những gì tôi sẽ làm nếu tôi không thể lên kế hoạch làm việc. Tôi thấy các luồng là một trong những khía cạnh khó hiểu hơn của C++, vì vậy tôi nghĩ đây có thể là một cách hay để hiểu sâu hơn về cách chúng hoạt động ... – user1898153

Trả lời

8

Các iostream hỗ trợ thêm dữ liệu tùy chỉnh cho chúng, vì vậy bạn không cần phải viết một lớp dẫn xuất đầy đủ chỉ để thêm một mức thụt đầu dòng sẽ được thao tác bởi người thao tác. Đây là một tính năng ít được biết đến của iostream, nhưng có ích ở đây.

Bạn sẽ viết thao tác của bạn như thế này:

/* Helper function to get a storage index in a stream */ 
int get_indent_index() { 
    /* ios_base::xalloc allocates indices for custom-storage locations. These indices are valid for all streams */ 
    static int index = ios_base::xalloc(); 
    return index; 
} 

ios_base& inc_ind(ios_base& stream) { 
    /* The iword(index) function gives a reference to the index-th custom storage location as a integer */ 
    stream.iword(get_indent_index())++; 
    return stream; 
} 

ios_base& dec_ind(ios_base& stream) { 
    /* The iword(index) function gives a reference to the index-th custom storage location as a integer */ 
    stream.iword(get_indent_index())--; 
    return stream; 
} 

template<class charT, class traits> 
basic_ostream<charT, traits>& endl_ind(basic_ostream<charT, traits>& stream) { 
    int indent = stream.iword(get_indent_index()); 
    stream.put(stream.widen('\n'); 
    while (indent) { 
     stream.put(stream.widen('\t'); 
     indent--; 
    } 
    stream.flush(); 
    return stream; 
} 
0

tôi đã kết hợp giải pháp Bart van Ingen Schenau với một khía cạnh, để cho phép đẩy và popping các cấp thụt đầu dòng để dòng sản lượng hiện có. Mã này hiện có sẵn trên github: https://github.com/spacemoose/ostream_indenter, và có một bản demo kỹ lưỡng hơn/kiểm tra trong kho, nhưng về cơ bản nó cho phép bạn làm như sau:

/// This probably has to be called once for every program: 
// http://stackoverflow.com/questions/26387054/how-can-i-use-stdimbue-to-set-the-locale-for-stdwcout 
std::ios_base::sync_with_stdio(false); 

std::cout << "I want to push indentation levels:\n" << indent_manip::push 
      << "To arbitrary depths\n" << indent_manip::push 
      << "and pop them\n" << indent_manip::pop 
      << "back down\n" << indent_manip::pop 
      << "like this.\n" << indent_manip::pop; 

Để sản xuất:

I want to push indentation levels: 
    To arbitrary depths 
     and pop them 
    back down 
like this. 

tôi đã để thực hiện một loại mẹo khó chịu, vì vậy tôi quan tâm đến việc nghe phản hồi về tiện ích mã.

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