1

I am new to C++ and am wondering if there is a more elegant way to print out the following:

Celsius  Kelvin  Fahrenheit  Reaumur
-------------------------------------

I guess you could just do

cout << "Celsius  Kelvin  Fahrenheit  Reaumur" << endl << "-------------------------------------";

But it doesn't look good. In Ada you could do "Width". Is there a similiar operator in cpp? And can you not just do setfill('-') and the amount of '-' you want to print out?

Any help is greatly appreciated

leun
  • 173
  • 10

4 Answers4

6

Here are two other ways to produce this line:

    std::cout << "-------------------------------------\n";

std::setfill + std::setw:

#include <iomanip>

    std::cout << std::setfill('-') << std::setw(38) << '\n';

Using a std::string:

#include <string>

    std::cout << std::string(37, '-') << '\n';

Demo

Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • Thank you! Do you mind telling me that '\n'; does? If it's a new line then why can't we just type endl; instead – leun Nov 29 '21 at 22:07
  • 1
    @leun You're welcome! Yes that's a newline and it's the preferred way unless you need to flush `stdout` (which `std::endl` does). Flushing comes with a cost and is rarely needed. – Ted Lyngmo Nov 29 '21 at 22:09
3

You could (and probably should) use std::format. Also see the fmtlib/fmt library:

Both format and fmtlib use the format spec':

Also see this question which features several related answers:


You can tweak this very easily to make this fit your needs (I made some deliberate imperfections for the sake of clarity):

#include <fmt/core.h>

int main() {
    int const width = 12;

    // See https://en.cppreference.com/w/cpp/utility/format/format
    // ^ centres the field (with default space fill)
    // -^ centres the field with "-" fill
    // 12 and 52 are specific field widths.
    // inner {} means the field width is provided by the next parameter

    fmt::print("_{:^{}} {:^{}} {:^{}} {:^12}_\n-{:-^52}\n", 
            "Celsius", width,
            "Kelvin", width,
            "Farenheit", width,
            "Reaumur",
            "=");
}

Output:

_  Celsius       Kelvin     Farenheit     Reaumur   _
--------------------------=--------------------------

FmtLib Demo: https://godbolt.org/z/463xWvx5P

Format Demo: https://godbolt.org/z/MP9sac7ba (thanks Ted)

Den-Jason
  • 2,395
  • 1
  • 22
  • 17
1

Big fan of separating this out for re-use and easier reading. Example:

std::ostream & draw_heading(std::ostream & out,
                            const std::string & heading)
{
    char old_fill = out.fill('-');
    std::streamsize old_width = out.width();
    out << h.mHeading << '\n'
        << std::setw(h.mHeading.size() + 1) << '\n';
    out.width(old_width);
    out.fill(old_fill);
    return out;
}

Only does the writing and will write to any output stream. It returns a reference to the stream so it can be easily tested for success or chained.

Basic Usage:

draw_heading(std::cout, "Celsius  Kelvin  Fahrenheit  Reaumur");

The ugly stuff is now buried away from the main logic, which can get on with whatever the heck its job is.

user4581301
  • 33,082
  • 7
  • 33
  • 54
  • The problem, of course, is that this magically changes the stream's fill character for unsuspecting users. – Dúthomhas Nov 29 '21 at 21:22
  • @Dúthomhas Woo. Hadn't thought of that and never had the problem. Probably because where it mattered I'd be setting the fill to `'0'` ahead of the numbers that followed or reflexively resetting the fill to space. I'll need to rethink a few helper functions I've dropped into my code. – user4581301 Nov 29 '21 at 21:25
  • 2
    `char ch = out.fill(); streamsize w = out.width(); out << ... << std::setfill(...) << std::setw(...) << ...; out.fill(ch); out.width(w);` Alternatively: `out << ...; char ch = out.fill(...); streamsize w = out.width(...); out << ...; out.fill(ch); out.width(w);` – Remy Lebeau Nov 29 '21 at 21:30
  • This exercise lead me to wondering if there's a good way [to do this](https://godbolt.org/z/aEnEhezKo) without the superfluous `string`. – user4581301 Nov 29 '21 at 21:47
  • Duh. `std::string_view` – user4581301 Nov 29 '21 at 22:18
1

You can use the literal string feature:

#include <string>
#include <iostream>

int main()
{
    std::cout << R"(
This is a line of text with an underline
----------------------------------------
)";

}

This allows you to add all the explicit characters you want (including newline) which makes the layout of large chunks of text nicer (relatively) to do in code.

I just wish that the R"( ignored the first newline if it is the only character on that line. But it still looks better than:

cout << "Celsius  Kelvin  Fahrenheit  Reaumur\n"
     << "------------------------------------\n";

or

cout << "Celsius  Kelvin  Fahrenheit  Reaumur\n"
     << std::string(38, '-') << "\n";
Martin York
  • 257,169
  • 86
  • 333
  • 562