【问题标题】:How to write an ostream operator with custom flags如何使用自定义标志编写 ostream 运算符
【发布时间】:2013-08-10 14:32:31
【问题描述】:

我经常想将 stl 容器写入 ostream。 以下代码可以正常工作(至少对于向量和列表):

template< typename T ,template<typename ELEM, typename ALLOC=std::allocator<ELEM> > class Container >
std::ostream& operator<< (std::ostream& o, Container<T>const & container){
  typename Container<T>::const_iterator beg = container.begin();
  while(beg != container.end()){
    o << *beg++;
    if (beg!=container.end())  o << "\t";
  }
  return o;
}

现在我想扩展此代码以支持可自定义的分隔符。以下方法显然行不通,因为该运算符应该只采用两个参数。

template< typename T ,template<typename ELEM, typename ALLOC=std::allocator<ELEM> > class Container >
std::ostream& operator<< (std::ostream& o, Container<T>const & container,char* separator){
  typename Container<T>::const_iterator beg = container.begin();
  while(beg != container.end()){
    o << *beg++;
    if (beg!=container.end())  o << separator;
  }
  return o;
}

不借助单例或全局变量可以实现这样的目标吗?

理想的情况是引入自定义标志或流操纵器,例如std::fixed。这样就可以写了

std::cout << streamflags::tabbed << myContainer;

【问题讨论】:

    标签: c++ io stream operator-overloading


    【解决方案1】:

    您可以编写自己的操纵器。 basic_ostream 提供 operator&lt;&lt; overloads that take a function pointer(参见链接中的 (9)),并调用该函数,将流本身作为参数传递。所以操纵器只是一个函数名。

    或者,操纵器可以是具有合适operator&lt;&lt; 的对象。这将允许你写,比如说,cout &lt;&lt; setSeparator(',') &lt;&lt; myContainer;。这里,setSeparator 是一个带有setSeparator(char) 构造函数的类。

    最后,ios_base 提供了xallociwordpword 成员,它们基本上允许将任意信息与特定流实例相关联。这就是您的机械手可以与您的operator&lt;&lt;(Container) 通信的方式。您确实需要一个全局变量来存储xalloc 为您分配的索引。

    【讨论】:

      【解决方案2】:

      为了完成@Igor-Tandetnik 的回答,一个简单的(不是线程安全的)更明确的例子:

      #include <iostream>             
      #include <vector>       
      
      namespace MyNamespace
      {
        namespace IO
        {
          enum class OrientationEnum
          {
            Row,
            Column
          };
      
          struct State
          {
            OrientationEnum orientation = OrientationEnum::Row;
          };
      
          static State currentState;
      
          template <typename CharT, typename Traits>
          inline std::basic_ostream<CharT, Traits>& rowOriented(
              std::basic_ostream<CharT, Traits>& os)
          {
            currentState.orientation = OrientationEnum::Row;
      
            return os;
          }
      
          template <typename CharT, typename Traits>
          inline std::basic_ostream<CharT, Traits>& columnOriented(
              std::basic_ostream<CharT, Traits>& os)
          {
            currentState.orientation = OrientationEnum::Column;
      
            return os;
          }
        }
      
        template <typename T>
        std::ostream& operator<<(std::ostream& out, const std::vector<T>& toPrint)
        {
          switch (IO::currentState.orientation)
          {
            case IO::OrientationEnum::Column:
              for (const auto& e : toPrint)
              {
                out << e << "\n";
              }
              break;
      
            case IO::OrientationEnum::Row:
              for (const auto& e : toPrint)
              {
                out << e << " ";
              }
              break;
      
            default:
              break;
          }
      
          return out;
        }
      }
      
      //////////////////////////////////////////////////////////////////
      
      using namespace MyNamespace;
      
      int main()
      {
        std::vector<int> v(5,0); // A 5-vector of 0 
      
        // If you want to save your state
        // auto savedState = IO::currentState;
      
        std::cout << "\nBy row\n"
                  << IO::rowOriented << v
                  //
                  << "\nBy column\n"
                  << IO::columnOriented << v;
      
        // IO::currentState = savedState;
      }
      

      你可以编译运行它。

      g++ streamExample.cpp -o streamExample
      ./streamExample
      

      输出是:

      By row
      0 0 0 0 0 
      By column
      0
      0
      0
      0
      0
      

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-12
      • 1970-01-01
      • 2011-11-03
      • 2011-01-15
      • 1970-01-01
      相关资源
      最近更新 更多