Как и в c мы можем использовать различные спецификаторы формата, такие как
Так есть ли способ использовать их с станд :: соиЬ ?
Я получил некоторые отрицательные отзывы в недавнем курсе (c ++ для c программистов) в Coursera, для использования Printf вместо соиЬ потому что я хотел немного форматирования 🙁
За %nd
%0nd
, Эквиваленты C ++ std::setw()
а также std::setfill()
,
#include <iostream> // std::cout, std::endl
#include <iomanip> // std::setfill, std::setw
int main () {
std::cout << std::setfill ('x') << std::setw (10);
std::cout << 77 << std::endl;
return 0;
}
Выход: xxxxxxxx77
%.nf
можно заменить на std::setprecision
а также std::fixed
,
#include <iostream> // std::cout, std::fixed, std::scientific
int main () {
double a = 3.1415926534;
double b = 2006.0;
double c = 1.0e-10;
std::cout.precision(5);
std::cout << "fixed:\n" << std::fixed;
std::cout << a << '\n' << b << '\n' << c << '\n';
return 0;
}
Выход:
fixed:
3.14159
2006.00000
0.00000
Поток C ++s не используют спецификаторы формата, такие как C printf()
функции типа; они используют manipulators
.
#include <iostream>
#include <iomanip>int main()
{
std::cout << std::fixed << std::setprecision(6) << 42.0 << std::endl;
}
42.000000
Обычное решение в C ++ состоит в том, чтобы определить манипуляторы, которые утверждают
что вы пытаетесь отформатировать, а не взламывать физические значения
прямо в точке выхода. (Одним из возможных исключений является
ширина, где std::setw
может быть полезным непосредственно.) Таким образом, для
Например, когда вы выводите что-то, вы не будете указывать
заполнение нулями, или фиксированное, с двумя десятичными знаками, но что-то вроде:
std::cout << temperature(2) << theTemporature;
где temperature
будет что-то вроде:
class temperature
{
int myMinWidth;
public:
temperature( int minWidth )
: myMinWidth( minWidth )
{
}
friend std::ostream& operator<<( std::ostream& dest, temperature const& manip )
{
dest.setf( std::ios_base::fixed, std::ios_base::floatfield );
dest.precision( 2 );
dest.width( myMinWidth );
return dest;
}
};
Список доступных модификаций формата см. В
спецификация std::ios_base
и поля
std::ios_base::fmtflags
,
Если вы делаете много выходных данных, вы можете изменить это
восстановить исходные флаги формата в конце полного
выражение. (Вся информация о формате, кроме ширины
липкий, поэтому принудительный фиксированный формат оставляет вас с фиксированным
формат для остальной части программы, что не обязательно, что
Вы хотите.) Я использую следующее в качестве базового класса для всех моих
манипуляторы:
class StateSavingManip
{
public:
void operator()( std::ios& stream ) const;
protected:
StateSavingManip() : myStream( nullptr ) {}
~StateSavingManip();
private:
virtual void setState( std::ios& stream ) const = 0;
private:
mutable std::ios* myStream;
mutable std::ios::fmtflags mySavedFlags;
mutable int mySavedPrec;
mutable char mySavedFill;
};
реализация:
namespace {
int getXAlloc() ;
int ourXAlloc = getXAlloc() + 1 ;
int
getXAlloc()
{
if ( ourXAlloc == 0 ) {
ourXAlloc = std::ios::xalloc() + 1 ;
assert( ourXAlloc != 0 ) ;
}
return ourXAlloc - 1 ;
}
}
StateSavingManip::~StateSavingManip()
{
if ( myStream != nullptr ) {
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 == nullptr ) {
backptr = const_cast< StateSavingManip* >( this ) ;
myStream = &stream ;
mySavedFlags = stream.flags() ;
mySavedPrec = stream.precision() ;
mySavedFill = stream.fill() ;
}
setState( stream ) ;
}
Обратите внимание на использование pword
поле, чтобы гарантировать, что только первый
временный манипулятор восстанавливает формат; деструкторы будут
называться в обратном порядке построения, но в порядке
конструкция, как правило, не будет указана, если у вас есть больше
чем один такой манипулятор в выражении.
Наконец: не все возможно с использованием этой техники: если вы
хочу систематически добавлять знак градуса к температуре,
нет способа сделать это. В этом случае вам нужно определить
Температура класса, и перегрузка <<
оператор для него; этот
позволяет все мыслимое (гораздо больше, чем вы могли когда-либо
достичь с printf
стиль форматирования).
C ++ потоковые манипуляторы (iomanip) были специально разработаны для поддержки всех стандартных операций спецификаторов формата c, только с совершенно другим интерфейсом. Например. setfill
а также setw
для ширины и заполнения части %02d
,
Конечно, если вам действительно нужны строки формата (например, потому что это облегчает i18n), то вам следует взглянуть на boost::format
и если у вас есть C ++ 11, то вы можете легко написать вокруг него небольшую переменную оболочку шаблона, чтобы вызов формата был больше похож на printf.
Что бы вы ни делали, пожалуйста, старайтесь не использовать printf. Он не безопасен для типов и не расширяется для операций вывода для пользовательских типов.
Есть потоковые манипуляторы, если они вам нужны.
Но я думаю, что вы хотите знать эту вещь:
cout
умнее чем printf()
,
Скажем, у вас есть:
int x = 34;
cout<<x;
Теперь компилятор вызовет:
ostream& operator<<(ostream& stream, int arg);
для тебя. И эта функция будет печатать вывод в консоли (так как в вашем случае stream
является cout
). Стандартная библиотека предоставляет перегрузки для этого <<
оператор для всех основных типов данных.