9

Vector私は C++ でクラスを作成しましたが、それは私の問題にうまく機能します。私は今それを片付けています、そして私は次のコードに出くわしました:

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;
} 

このコードでは、ベクトルを として出力できますstd::cout<<v<<std::endl;。各数値には 23 個のスペースがあり、そのうち 16 個は小数です。テキストは、印刷されるように右揃えになります。

 1.123456123456e+01
-1.123456123456e+01

それ以外の

1.123456123456e+01
-1.123456123456e+01

コードは非常に繰り返しのようです。「標準的な方法で文字を印刷しますが、この指定された形式で数字を印刷する」のようなことができるように、どのように形式 (すべてのsetiosflags,setwおよびステートメント)を「保存」できますか。setprecision

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

編集

Rob Adams のコメントに従って、私は醜いコード (他の人が指摘したように、「次の男」の精度を台無しにする) をより簡潔な (そして正しい) に変更しました。

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;
}
4

4 に答える 4

11

あくまでstd::setw()一時的なものです。他の 2 つの呼び出し 、setiosflagsおよび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;
} 

しかし今、あなたは次の男のためにフラグと精度を破った. 代わりにこれを試してください:

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;
} 

幅を永続的にすることはできないと彼らが判断したこの他の質問も参照してください。

于 2011-03-16T17:03:25.270 に答える
3

C++20 では、次のことができます。

std::ostream& operator<<(std::ostream& output, const Vector& v){
  const int width = 23, precision = 16;
  return output << std::format(
      "[{0:{3}.{4}e}, {1:{3}.{4}e}, {2:{3}.{4}e}]",
      v._x, v._y, v._z, width, precision);
} 

I/O マニピュレータとは異なり、のフォーマット状態std::formatは変更されないためostream、Bo Persson が言及した問題を回避できます。

あなたの本当の問題は、この後の次の出力に何が起こるかです...

また、I/O マニピュレータは で正しく動作しVectorます。

が利用可能になるまでは、ベースとなっている {fmt} ライブラリstd::formatを使用できます。

于 2021-03-03T04:58:37.257 に答える
2

通常、標準のマニピュレータを直接使用することはありません。この場合、たとえば、マニピュレータ 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;
}

もちろん、これにより、後のユーザーのためにフォーマットのほとんどが変更されます。一般に、状態を保存し、それをデストラクタで復元する一時クラス オブジェクトを使用することをお勧めします。私は通常、マニピュレーターを次のようなものから派生させます。

header: class StateSavingManip { public: StateSavingManip( StateSavingManip const& other ) ;

    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 << ']';

(賢い人なら、それらを回避する方法を見つけ出すと思いますが、私は気にしたことがないので、気にしませんでした。)

于 2011-03-16T17:40:14.403 に答える
2

setw() 以外のすべては、実際にすでにそれを行っています。彼らは「粘着性」です。

あなたの本当の問題は、この後の次の出力に何が起こるかです...

于 2011-03-16T16:57:17.047 に答える