Как понять противоречивое поведение C++ std::setw?
Учитывая следующий код:
/*Formatting Output
**Goal: practice using cout to format output to console
**Print the variables in three columns:
**Ints, Floats, Doubles
*/
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
int a = 45;
float b = 45.323;
double c = 45.5468;
int aa = a + 9;
float bb = b + 9;
double cc = c + 9;
int aaa = aa + 9;
float bbb = bb + 9;
double ccc = cc + 9;
// 1st attempt :>
cout << "\n\n\n" << "// 1st attempt :>" << "\n";
cout << "12345678901234567890123456789012345678901234567890" << "\n";
cout << "Ints" << setw(15) << "Floats" << setw(15) << "Doubles" << "\n";
cout << a << setw(15) << b << setw(15) << c << "\n";
cout << aa << setw(15) << bb << setw(15) << cc << "\n";
cout << aaa << setw(15) << bbb << setw(15) << ccc << "\n";
// 2nd attempt :>
cout << "\n\n\n" << "// 2nd attempt :>" << "\n";
cout << "12345678901234567890123456789012345678901234567890" << "\n";
cout << std::left << std::setfill(' ') << std::setw(15) << "Ints" << setw(15) << "Floats" << setw(15) << "Doubles" << "\n";
cout << a << setw(15) << b << setw(15) << c << "\n";
cout << std::left << std::setfill(' ') << setw(15) << aa << setw(15) << bb << setw(15) << cc << "\n";
cout << aaa << setw(15) << bbb << setw(15) << ccc << "\n";
// 3rd attempt :>
cout << "\n\n\n" << "// 3rd attempt :>" << "\n";
cout << "12345678901234567890123456789012345678901234567890" << "\n";
cout << std::left << std::setfill(' ') << std::setw(15) << "Ints" << setw(15) << "Floats" << setw(15) << "Doubles" << "\n";
cout << std::left << std::setfill(' ') << std::setw(15) << a << setw(15) << b << setw(15) << c << "\n";
cout << std::left << std::setfill(' ') << std::setw(15) << aa << setw(15) << bb << setw(15) << cc << "\n";
cout << std::left << std::setfill(' ') << std::setw(15) << aaa << setw(15) << bbb << setw(15) << ccc << "\n";
cout << "12345678901234567890123456789012345678901234567890" << "\n";
cout << std::right << std::setfill(' ') << std::setw(15) << "Ints" << setw(15) << "Floats" << setw(15) << "Doubles" << "\n";
cout << std::right << std::setfill(' ') << std::setw(15) << a << setw(15) << b << setw(15) << c << "\n";
cout << std::right << std::setfill(' ') << std::setw(15) << aa << setw(15) << bb << setw(15) << cc << "\n";
cout << std::right << std::setfill(' ') << std::setw(15) << aaa << setw(15) << bbb << setw(15) << ccc << "\n";
return 0;
}
// https://repl.it/@Tredekka/Cpp-Understanding-stdsetw
... я получаю следующий вывод:
gcc version 4.6.3
// 1st attempt :>
12345678901234567890123456789012345678901234567890
Ints Floats Doubles
45 45.323 45.5468
54 54.323 54.5468
63 63.323 63.5468
// 2nd attempt :>
12345678901234567890123456789012345678901234567890
Ints Floats Doubles
4545.323 45.5468
54 54.323 54.5468
6363.323 63.5468
// 3rd attempt :>
12345678901234567890123456789012345678901234567890
Ints Floats Doubles
45 45.323 45.5468
54 54.323 54.5468
63 63.323 63.5468
12345678901234567890123456789012345678901234567890
Ints Floats Doubles
45 45.323 45.5468
54 54.323 54.5468
63 63.323 63.5468
... примечание: я намеренно был "несовместим" с кодом, "потому что" я пытаюсь понять поведение <iomanip>
&& std::setw()
код.
Если вы посмотрите на вывод с 1-й попытки, то заметите, что вывод "строки" строки заголовка смещен от "числового" вывода строк данных... и хотя он "в основном" выполняет задачу выравнивания элементов в столбцах Это не точно и не соответствует.
Во 2-й попытке вы увидите, что я обнаружил, что если я добавлю вывод строки с помощью:
<< std::left << std::setfill(' ') << setw(15)
... тогда я получаю строку, которая выглядит правильно (как видно из заголовка и второй строки данных)... но теперь вы заметите, что первая и третья строки данных очень неправильны:
4545.323 45.5468
...
6363.323 63.5468
... как происходит "использование / выполнение"...
<< std::left << std::setfill(' ') << setw(15)
... влияет на "будущие" казни setw()
?
Ради полноты я показал в 3-й попытке, что можно правильно и точно выровнять столбцы данных (влево или вправо), используя <iomanip>
&& std::setw()
... но почему несоответствия?
(Ответ @WhozCraig помог мне добраться до того места, где я нахожусь, но не углубился достаточно глубоко, чтобы помочь мне понять также: (a) почему это "псевдо" работает || (b) почему после того, как вы заставили его работать правильно "в первый раз" затем он нарушает функциональность "псевдо".)
2 ответа
Причиной того, что вы говорите, является "непоследовательность", является тот факт, что вы не знаете, как std::setw()
, Он не печатает первый символ каждые 15 позиций, скорее он печатает 15 пробелов после последнего символа. Так чтобы получить consistant
Значение, которое вы должны выровнять по правому краю в первом ряду.
cout << setw(4) << "Ints" << setw(15) << "Floats" << setw(15) << "Doubles" << "\n";
cout << setw(4) << a << setw(15) << b << setw(15) << c << "\n";
cout << setw(4) << aa << setw(15) << bb << setw(15) << cc << "\n";
cout << setw(4) << aaa << setw(15) << bbb << setw(15) << ccc << "\n";
Это даст следующий результат:
Ints Floats Doubles
45 45.323 45.5468 // in this line setw() counts 15 spaces from number 5.
54 54.323 54.5468
63 63.323 63.5468
Вот ваша проблема:
std::setw()
не действует как буфер, он изменяет способ вычисления следующего выражения.
Вам необходимо понимать «диапазон», который имеет каждое из этих выражений. Конкретно,
std::setfill(int)
и / изменить поведение по умолчанию и казаться последним, пока они не будут перезаписаны другим
setfill()
или же
std::left
/
std::right
.
std::setw(int)
с другой стороны, похоже, влияет только на то, что передается сразу после него (что странно, потому что я чувствую, что также видел, как он ведет себя как
std::setfill
и другие раньше)
Итак, чтобы подвести итог, вы хотите чего-то более похожего на это:
int a = 45;
float b = 45.323;
double c = 45.5468;
int aa = a + 9;
float bb = b + 9;
double cc = c + 9;
int aaa = aa + 9;
float bbb = bb + 9;
double ccc = cc + 9;
std::cout << std::endl << std::endl << std::endl;
std::cout << std::left << std::setfill('~');
// 1st attempt :>
std::cout << "// 1st attempt :>" << std::endl;
std::cout << "12345678901234567890123456789012345678901234567890" << std::endl;
std::cout << std::setw(10) << "Ints" << std::setw(10) << "Floats" << std::setw(10) << "Doubles" << std::endl;
std::cout << std::setw(10) << a << std::setw(10) << b << std::setw(10) << c << std::endl;
std::cout << std::setw(10) << aa << std::setw(10) << bb << std::setw(10) << cc << std::endl;
std::cout << std::setw(10) << aaa << std::setw(10) << bbb << std::setw(10) << ccc << std::endl;
std::cout << std::endl << std::endl << std::endl << std::setfill('*');
// 2nd attempt :>
std::cout << "// 2nd attempt :>" << std::endl;
std::cout << "12345678901234567890123456789012345678901234567890" << std::endl;
std::cout << std::setw(10) << "Ints" << std::setw(10) << "Floats" << std::setw(10) << "Doubles" << std::endl;
std::cout << std::setw(10) << a << std::setw(10) << b << std::setw(10) << c << std::endl;
std::cout << std::setw(10) << aa << std::setw(10) << bb << std::setw(10) << cc << std::endl;
std::cout << std::setw(10) << aaa << std::setw(10) << bbb << std::setw(10) << ccc << std::endl;
std::cout << std::endl << std::endl << std::endl;
// 3rd attempt :>
std::cout << "// 3rd attempt :>" << std::endl;
std::cout << "12345678901234567890123456789012345678901234567890" << std::endl;
std::cout << std::setw(10) << "Ints" << std::setw(10) << "Floats" << std::setw(10) << "Doubles" << std::endl;
std::cout << std::setw(10) << a << std::setw(10) << b << std::setw(10) << c << std::endl;
std::cout << std::setw(10) << aa << std::setw(10) << bb << std::setw(10) << cc << std::endl;
std::cout << std::setw(10) << aaa << std::setw(10) << bbb << std::setw(10) << ccc << std::endl;
std::cout << "12345678901234567890123456789012345678901234567890" << std::endl;
std::cout << std::right << std::setfill(' ');
std::cout << std::setw(10) << "Ints" << std::setw(10) << "Floats" << std::setw(10) << "Doubles" << std::endl;
std::cout << std::setw(10) << a << std::setw(10) << b << std::setw(10) << c << std::endl;
std::cout << std::setw(10) << aa << std::setw(10) << bb << std::setw(10) << cc << std::endl;
std::cout << std::setw(10) << aaa << std::setw(10) << bbb << std::setw(10) << ccc << std::endl;
std::cout << std::endl << std::endl << std::endl;
(Вы заметите, что я тоже изменился
"\n"
к
std::endl
который дополнительно очищает буфер после каждой строки.)