2011-03-16 4 views
7

私はVectorクラスをC++で作成しました。私は今それをクリーンアップしています、と私は次のコードに走った:コードはstd::cout<<v<<std::endl;としてベクトルを印刷することができますC++ iomanipライブラリの効果的な使用

std::ostream& operator<<(std::ostream &output, const Vector &v){ 
    output<<"[" 
    <<std::setiosflags(std::ios::right | std::ios::scientific) 
    <<std::setw(23) 
    <<std::setprecision(16) 
    <<v._x<<", " 
    <<std::setiosflags(std::ios::right | std::ios::scientific) 
    <<std::setw(23) 
    <<std::setprecision(16) 
    <<v._y<<", " 
    <<std::setiosflags(std::ios::right | std::ios::scientific) 
    <<std::setw(23) 
    <<std::setprecision(16) 
    <<v._z<<"]"; 
    return output; 
} 

。各数字には23のスペースがあり、そのうち16は小数です。それが印刷されるように、テキストは右揃えです:

1.123456123456e+01 
-1.123456123456e+01 

代わりの

1.123456123456e+01 
-1.123456123456e+01 

コードがひどく反復ようです。どのように "標準的な方法で文字を印刷するが、この指定された形式の数字"のように言うことができるように、フォーマット(すべて、setwおよびsetprecisionステートメント)を「保存」することができます。

ありがとうございました!

編集

ロブアダムスのコメントごとに、私はより簡潔に(他の人が指摘したように、 『隣の男』のためだろう台無し精度を)私の醜いコードを変更したよう(と正しい):

std::ostream& operator<<(std::ostream &output, const Vector &v){ 
    std::ios_base::fmtflags f = output.flags(std::ios::right | std::ios::scientific); 
    std::streamsize p = output.precision(16); 
    output<<"[" 
    <<std::setw(23)<<v._x<<", " 
    <<std::setw(23)<<v._y<<", " 
    <<std::setw(23)<<v._z 
    <<"]"; 
    output.flags(f); 
    output.precision(p); 
    return output; 
} 
+0

かなりの複製http://stackoverflow.com/questions/405039/permanent-stdsetw –

答えて

10

のみstd::setw()は一時的なものです。他の2つのコール、、およびsetprecisionは永続的な影響を与えます。

だから、あなたがするようにコードを変更することができます:

std::ostream& operator<<(std::ostream &output, const Vector &v){ 
    output<<"[" 
    <<std::setiosflags(std::ios::right | std::ios::scientific) 
    <<std::setw(23) 
    <<std::setprecision(16) 
    <<v._x<<", " 
    <<std::setw(23) 
    <<v._y<<", " 
    <<std::setw(23) 
    <<v._z<<"]"; 
    return output; 
} 

しかし、今は隣の男のためのフラグと精度をborkedました。代わりにこれを試してみてください:

最後に
std::ostream& operator<<(std::ostream &output, const Vector &v){ 
    std::ios_base::fmtflags f = output.flags(std::ios::right | std::ios::scientific); 
    std::streamsize p = output.precision(16); 
    output<<"[" 
    <<std::setw(23) 
    <<v._x<<", " 
    <<std::setw(23) 
    <<v._y<<", " 
    <<std::setw(23) 
    <<v._z<<"]"; 
    output.flags(f); 
    output.precision(p); 
    return output; 
} 

、あなたは絶対に一定の23の重複を取り除くために持っている場合、あなたはこのような何かを行うことができます(しかし、私はそれをお勧めしません):

struct width { 
    int w; 
    width(int w) : w(w) {} 
    friend std::ostream& operator<<(std::ostream&os, const width& w) { 
    return os << std::setw(width.w); 
    } 
}; 


std::ostream& operator<<(std::ostream &output, const Vector &v){ 
    std::ios_base::fmtflags f = output.flags(std::ios::right | std::ios::scientific); 
    std::streamsize p = output.precision(16); 
    width w(23); 
    output<<"[" 
    <<w 
    <<v._x<<", " 
    <<w 
    <<v._y<<", " 
    <<w 
    <<v._z<<"]"; 
    output.flags(f); 
    output.precision(p); 
    return output; 
} 

this other questionも参照してください。ここでは、幅を固定することはできません。

+0

多くのありがとう私の問題を解決するだけでなく、タ一般的なストリームのコンセプトに関する何かを私に奪われた。ありがとう! – Escualo

1

実際にはsetw()を除くすべてが実際にそれを行います。彼らは "粘着性"です。あなたの本当の問題はこの1つの後、次の出力がどうなるかである

...

1

通常、標準マニピュレータは直接使用しません。 この場合、例えば、あなたがマニピュレータ fromVectorを定義し、それを使用する可能性があります:あなたは幅とベクトルで 要素の精度を変更したい場合は

output << '[' 
     << fromVector << v.x << ", " 
     << fromVector << v.y << ", " 
     << fromVector << v.z << ']'; 

そのように、あなただけに持っています1か所でやりなさい。もちろん

std::ostream& fromVector(std::ostream& stream) 
{ 
    stream.setf(std::ios::right, std::ios::adjustfield); 
    stream.setf(std::ios::scientific, std::ios::floatfield); 
    stream.precision(16); 
    stream.width(32); 
    return stream; 
} 

が、これはどの 後のユーザーのためのフォーマットのほとんどを変更しています:マニピュレータは引数を持っていないこの場合、

、すべてのことが 必要なのは、単純な関数です。一般に、 を使用して状態を保存する一時クラスオブジェクトを使用し、デストラクタに を復元する方が良いでしょう。

ヘッダー: クラスStateSavingManip { 公共:私は通常のように なものから私のマニピュレータを導き出す StateSavingManip( StateSavingManipのconstの他&)。

virtual    ~StateSavingManip() ; 
    void    operator()(std::ios& stream) const ; 

protected: 
         StateSavingManip() ; 

private: 
    virtual void  setState(std::ios& stream) const = 0 ; 

private: 
    StateSavingManip& operator=(StateSavingManip const&) ; 

private: 
    mutable std::ios* myStream ; 
    mutable std::ios::fmtflags 
         mySavedFlags ; 
    mutable int   mySavedPrec ; 
    mutable char  mySavedFill ; 
} ; 

inline std::ostream& 
operator<<(
    std::ostream&  out, 
    StateSavingManip const& 
         manip) 
{ 
    manip(out) ; 
    return out ; 
} 

inline std::istream& 
operator>>(
    std::istream&  in, 
    StateSavingManip const& 
         manip) 
{ 
    manip(in) ; 
    return in ; 
} 

ソース: int getXAlloc(); int ourXAlloc = getXAlloc()+ 1;

int 
getXAlloc() 
{ 
    if (ourXAlloc == 0) { 
     ourXAlloc = std::ios::xalloc() + 1 ; 
     assert(ourXAlloc != 0) ; 
    } 
    return ourXAlloc - 1 ; 
} 
} 

StateSavingManip::StateSavingManip() 
    : myStream(NULL) 
{ 
} 

StateSavingManip::StateSavingManip(
    StateSavingManip const& 
         other) 
{ 
    assert(other.myStream == NULL) ; 
} 

StateSavingManip::~StateSavingManip() 
{ 
    if (myStream != NULL) { 
     myStream->flags(mySavedFlags) ; 
     myStream->precision(mySavedPrec) ; 
     myStream->fill(mySavedFill) ; 
     myStream->pword(getXAlloc()) = NULL ; 
    } 
} 

void 
StateSavingManip::operator()( 
    std::ios&   stream) const 
{ 
    void*&    backptr = stream.pword(getXAlloc()) ; 
    if (backptr == NULL) { 
     backptr  = const_cast< StateSavingManip* >(this) ; 
     myStream  = &stream ; 
     mySavedFlags = stream.flags() ; 
     mySavedPrec = stream.precision() ; 
     mySavedFill = stream.fill() ; 
    } 
    setState(stream) ; 
} 

あなたがこれを行う場合、あなたは マニピュレータ、例えば後に括弧を追加する必要があります:

output << '[' 
     << fromVector() << v.x << ", " 
     << fromVector() << v.y << ", " 
     << fromVector() << v.z << ']'; 

(私はいくつかの巧妙な魂は避け の方法を把握することを確信しています彼らは私を悩ましたことはありませんでしたので、私は が悩まされていません。)

関連する問題