2011-03-16 31 views
7

C++ 'da bir Vector sınıfı oluşturdum ve sorunlarım için harika çalışıyor. Hala da öyle temizliyorum, ben aşağıdaki kod parçası koştu:C++ iomanip kitaplığının etkin kullanımı

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

kod std::cout<<v<<std::endl; gibi bir vektör yazdırmak için izin verir. Her sayının 16'sı ondalık olan 23 alan vardır. o yazdırmak böylece metin sağa hizalanmış:

1.123456123456e+01 
-1.123456123456e+01 

yerine

1.123456123456e+01 
-1.123456123456e+01 

kodu müthiş tekrarlayan görünüyor. Biçimi (", setw ve setprecision deyimleri)" nasıl saklayabilirsiniz "gibi bir şeyi" karakterleri standart bir şekilde yazdır, ancak bu biçimdeki sayıları "gibi bir şekilde söyleyebilirsiniz.

Teşekkür ederiz! Rob Adams'ın comment gereğince

Düzenleme

, benim çirkin kod değişti (başkaları tarafından da belirttiği gibi, hangi, pisliği 'gelecek adam' için hassas olur) (daha az ve öz ve doğru):

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 –

cevap

10

Sadece std::setw() geçicidir. Diğer iki çağrı, ve setprecision kalıcı bir etkiye sahiptir.

Yani, kodunuzu değiştirebilir:

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

Ama şimdi bir sonraki adam için bayraklar ve hassasiyet borked ettik. Kesinlikle sabit 23 çoğaltılması kurtulmak varsa

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

Son olarak, böyle bir şey yapabileceğini (ama tavsiye etmem): Bu yolu deneyin

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

Ayrıca, genişliği kalıcı yapamayacağınıza karar verdikleri this other question'a da bakınız.

+0

bir kopyasının pek çoğunu değil. sorunumu çöz, ama aynı zamanda genel akım kavramı hakkında bana bir şey anlattı. Teşekkürler! – Escualo

1

Ancak, ancak setw() aslında bunu zaten yapar. Onlar "yapışkan". Gerçek sorun bu bir sonraki çıkışına ne olduğudur

...

1

Genel olarak, standart manipülatörleri doğrudan kullanmazsınız. Bu durumda, örneğin, bir manipülatör fromVector tanımlamak ve bu kullanabilirsiniz: Eğer genişlik ve vektör içinde elemanlarının hassasiyetini değiştirmek isterseniz

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

Bu şekilde, yalnızca zorunda tek bir yerde yap.Tabii

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

, bu herhangi bir sonra kullanmak üzere biçimlendirme çoğu değişmiş olacaktır: manipülatör hiçbir argüman vardır Bu durumda,

, bütün bu ihtiyaç duyulan basit bir işlevdir. Genel olarak, 'u, durumu kaydeden geçici bir sınıf nesnesi kullanmak daha iyi olur ve bu, 'u imha makinesinde geri yükler. ; StateSavingManip (& diğer StateSavingManip const):

başlık: sınıf StateSavingManip { kamu Genellikle gibi şey benim Dalaverecileri türetmek

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

kaynağı int getXAlloc(); int ourXAlloc = getXAlloc() + 1; Bunu yaparsanız

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

, sen manipülatör sonra parantez eklemek gerekecek örn:

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

(bazı akıllı ruh kaçınarak bir yolunu eminim onlar, ama onlar beni hiç rahatsız etmediler, bu yüzden ben rahatsız etmedim.)

İlgili konular