【问题标题】:c++ custom output stream with indentation带有缩进的 c++ 自定义输出流
【发布时间】:2012-11-30 07:54:15
【问题描述】:

我在尝试实现自定义流类以在输出文件中生成良好缩进的代码时遇到了一些麻烦。我在网上进行了广泛的搜索,但似乎没有就实现这一目标的最佳方式达成共识。有些人谈论派生流,其他人谈论派生缓冲区,还有一些人建议使用语言环境/构面等。

基本上,我发现自己写了很多这样的代码:

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

当标签开始加起来时,它看起来很糟糕,看起来有这样的东西会很好:

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;

即创建一个派生流类来跟踪其当前的缩进深度,然后创建一些操纵器来增加/减小缩进深度,以及一个操纵器来编写一个换行符,然后是多个制表符。

所以这是我实现类和操纵器的尝试:

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;
}

这会构建,但不会生成预期的输出;任何使用自定义操纵器的尝试都会导致它们由于某种原因被转换为布尔值并将“1”写入文件。我需要为我的新类重载

谢谢!

附言

1) 我已经从我的代码 sn-ps 中省略了#includes、使用命名空间等以节省空间。

2) 我的目标是能够使用类似于我的第二个代码 sn-p 中的接口。如果在阅读整篇文章后,您认为这是一个坏主意,请解释原因并提供替代方案。

【问题讨论】:

  • 问题:如果期望的结果是干净的代码和正确的输出——也就是说,如果这不仅仅是学术上的或为了你自己的进步——为什么要直接用这种方式编写 [HT|X]ML?至少,您可以将它写入光盘 UNindented,然后使用一些美化器(例如,整洁)来完成这项肮脏的工作。 ...话虽如此,这很有趣,而且我有一种油腻的感觉,我很快就会拼凑出一个解决方案。 :)
  • 嗨 - 这是一个好主意,如果我无法让计划 A 发挥作用,我可能最终会做什么。我发现流是 C++ 中更令人困惑的方面之一,所以我认为这可能是深入了解它们如何工作的好方法......

标签: c++ stl stream derived manipulators


【解决方案1】:

iostream 支持向它们添加自定义数据,因此您无需编写完整的派生类来添加将由操纵器操作的缩进级别。这是 iostreams 鲜为人知的特性,但在这里派上用场。

你会这样写你的操纵器:

/* 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;
}

【讨论】:

    【解决方案2】:

    我将 Bart van Ingen Schenau 的解决方案与一个方面相结合,以允许将缩进级别推送和弹出到现有输出流。代码在 github 上可用:https://github.com/spacemoose/ostream_indenter,并且在存储库中有更彻底的演示/测试,但基本上它允许您执行以下操作:

    /// 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;
    

    生产:

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

    我不得不做一个讨厌的把戏,所以我很想听听关于代码实用程序的反馈。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-12-04
      • 1970-01-01
      • 2019-04-23
      • 1970-01-01
      • 2013-03-13
      • 1970-01-01
      • 2020-08-21
      相关资源
      最近更新 更多