[英]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.