[英]How to write an ostream operator with custom flags
我经常想将 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;
您可以编写自己的操纵器。 basic_ostream
提供接受函数指针的operator<<
重载(请参阅链接中的 (9)),并调用该函数并将流本身作为参数传递。 所以操纵器只是一个函数名。
或者,操纵器可以是具有合适operator<<
的对象。 这将允许您编写cout << setSeparator(',') << myContainer;
. 这里, setSeparator
是一个带有setSeparator(char)
构造函数的类。
最后, ios_base
提供了xalloc
、 iword
和pword
成员,它们基本上允许将任意信息与特定流实例相关联。 这就是您的操纵器可以与您的operator<<(Container)
进行通信的方式。 您确实需要一个全局变量来存储xalloc
为您分配的索引。
为了完成@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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.