Formato in virgola mobile per std :: ostream

Come faccio quanto segue con std :: cout?

double my_double = 42.0; char str[12]; printf_s("%11.6lf", my_double); // Prints " 42.000000" 

Sono quasi pronto a rinunciare e usare sprintf_s.

Più in generale, dove posso trovare un riferimento sulla formattazione std :: ostream che elenca tutto in un unico posto, piuttosto che diffonderlo in un lungo tutorial?

EDIT 21 dic 2017 – Guarda la mia risposta qui sotto. Usa funzionalità che non erano disponibili quando ho posto questa domanda nel 2012.

 std::cout < < std::fixed << std::setw( 11 ) << std::setprecision( 6 ) << my_double; 

Devi aggiungere

 #include  

Hai bisogno di manipolatori di stream

Puoi "riempire" i posti vuoti con qualunque carattere tu voglia. Come questo:

 std::cout < < std::fixed << std::setw( 11 ) << std::setprecision( 6 ) << std::setfill( '0' ) << my_double; 
 std::cout < < boost::format("%11.6f") % my_double; 

Devi #include

 #include  #include  int main() { double my_double = 42.0; std::cout < < std::fixed << std::setw(11) << std::setprecision(6) << my_double << std::endl; return 0; } 

In generale, si vuole evitare di specificare cose come 11 e 6 sul punto di uscita. Questo è un markup fisico e vuoi un markup logico; ad es. pressure o volume . In questo modo, in un unico punto definisci come viene formattata la pressione o il volume e, se la formattazione cambia, non devi cercare attraverso il programma per trovare dove cambiare il formato (e cambiare accidentalmente il formato di qualcos’altro) . In C ++, lo fai definendo un manipolatore, che imposta le varie opzioni di formattazione e le ripristina preferibilmente alla fine dell’espressione completa. Quindi finisci per scrivere cose come:

 std::cout < < pressure << my_double; 

Anche se io sicuramente non lo FFmt nel codice di produzione, ho trovato il seguente formattatore FFmt utile per lavori veloci:

 class FFmt : public StateSavingManip { public: explicit FFmt( int width, int prec = 6, std::ios::fmtflags additionalFlags = static_cast(), char fill = ' ' ); protected: virtual void setState( std::ios& targetStream ) const; private: int myWidth; int myPrec; std::ios::fmtflags myFlags; char myFill; }; FFmt::FFmt( int width, int prec, std::ios::fmtflags additionalFlags, char fill ) : myWidth( width ) , myPrec( prec ) , myFlags( additionalFlags ) , myFill( fill ) { myFlags &= ~ std::ios::floatfield myFlags |= std::ios::fixed if ( isdigit( static_cast< unsigned char >( fill ) ) && (myFlags & std::ios::adjustfield) == 0 ) { myFlags |= std::ios::internal } } void FFmt::setState( std::ios& targetStream ) const { targetStream.flags( myFlags ) targetStream.width( myWidth ) targetStream.precision( myPrec ) targetStream.fill( myFill ) } 

Questo permette di scrivere cose come:

 std::cout < < FFmt( 11, 6 ) << my_double; 

E per la cronaca:

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

StateSavingManip.cc:

 namespace { // We maintain the value returned by ios::xalloc() + 1, and not // the value itself. The actual value may be zero, and we need // to be able to distinguish it from the 0 resulting from 0 // initialization. The function getXAlloc() returns this value // -1, so we add one in the initialization. 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 ); } 

sono io, l’OP, Jive Dadson – cinque anni dopo. C ++ 17 sta diventando una realtà.

L’avvento dei parametri di modelli variadici con l’inoltro perfetto ha reso la vita molto più semplice. La follia incatenata di ostream < < e boost :: format% può essere eliminata. La funzione oprintf sotto riempie il conto. Lavori in corso. Sentiti libero di gestire gli errori, ecc ...

 #include  #include  #include  #include  namespace dj { template Out& oprintf(Out &out, const std::string_view &fmt, Args&&... args) { const int sz = 512; char buffer[sz]; int cx = snprintf(buffer, sz, fmt.data(), std::forward(args)...); if (cx >= 0 && cx < sz) { return out.write(buffer, cx); } else if (cx > 0) { // Big output std::string buff2; buff2.resize(cx + 1); snprintf(buff2.data(), cx, fmt.data(), std::forward(args)...); return out.write(buff2.data(), cx); } else { // Throw? return out; } } } int main() { const double my_double = 42.0; dj::oprintf(std::cout, "%s %11.6lf\n", "My double ", my_double); return 0; } 

Per i futuri visitatori che preferiscono le attuali specifiche di formato printf con std :: ostream, ecco un’altra variazione, basata sull’eccellente post di Martin York in un’altra domanda SO: https://stackoverflow.com/a/535636 :

 #include  #include  #include  //snprintf class FMT { public: explicit FMT(const char* fmt): m_fmt(fmt) {} private: class fmter //actual worker class { public: explicit fmter(std::ostream& strm, const FMT& fmt): m_strm(strm), m_fmt(fmt.m_fmt) {} //output next object (any type) to stream: template std::ostream& operator< <(const TYPE& value) { // return m_strm << "FMT(" << m_fmt << "," << value << ")"; char buf[40]; //enlarge as needed snprintf(buf, sizeof(buf), m_fmt, value); return m_strm << buf; } private: std::ostream& m_strm; const char* m_fmt; }; const char* m_fmt; //save fmt string for inner class //kludge: return derived stream to allow operator overloading: friend FMT::fmter operator<<(std::ostream& strm, const FMT& fmt) { return FMT::fmter(strm, fmt); } }; 

esempio di utilizzo:

 double my_double = 42.0; cout < < FMT("%11.6f") << my_double << "more stuff\n"; 

o anche:

 int val = 42; cout < < val << " in hex is " << FMT(" 0x%x") << val << "\n";