我经常想把一个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;
答案 0 :(得分:4)
你可以编写自己的操纵器。 basic_ostream
提供operator<<
overloads that take a function pointer(请参阅链接中的(9)),并调用该函数将流本身作为参数传递。所以操纵器只是一个函数名。
或者,操纵器可以是具有合适operator<<
的对象。这样你就可以写cout << setSeparator(',') << myContainer;
了。在这里,setSeparator
是一个带有setSeparator(char)
构造函数的类。
最后,ios_base
提供了xalloc
,iword
和pword
成员,它们基本上允许用户将任意信息与特定的流实例相关联。这就是你的操纵者可以与你的operator<<(Container)
进行通信的方式。您需要一个全局变量来存储由xalloc
为您分配的索引。
答案 1 :(得分:0)
完成@ 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