0

I am very new to C++ ,I am solving a basic payroll and my target output is: output

however I am having troubles aligning the output. I must use setw() btw. Here's just an example.

    cout << setw(25) << left << "Employee ID: "<< emp_id <<setw(25)<<"Payroll Period: "<<date<<endl;

It is making 2 columns perfectly but the variable joins the second column. I tried removing the setw() at the beginning and it solved it however it is getting pushed causing the nxt column to move. output of code

  • 2 times `setw` makes 2 columns if you want 3 columns use 3 times `setw`. Please include acutal and desired output as text in the question – 463035818_is_not_an_ai Oct 18 '22 at 10:32
  • You should provide a more complex example – but usually it is of little use if you align the *constant* parts of your strings. I'd rather assume `emp_id` and possibly (depending on format) `date` differ in sizes, so you might want to adjust these two with `setw` instead. – Aconcagua Oct 18 '22 at 10:35
  • My desired output is not exatly what's provided I'm sorry. I wanted to know how to implement this: `Employee ID: 1010101 Date: January 1, 2022` `Employee Name: Someone Name Employee Salary: 120000` a perfectly align data in columns where 1 column has a string and a variable – foxxxxxxxxx Oct 18 '22 at 10:37
  • 2
    you can [edit](https://stackoverflow.com/posts/74109430/edit) the question to add the output you want. Formatting in comments is not clear, line breaks and stuff gets messed up – 463035818_is_not_an_ai Oct 18 '22 at 10:42
  • Are you familiar with `std::ostringstream`, and know how to use it? – Sam Varshavchik Oct 18 '22 at 10:59

1 Answers1

0

You seem to have a wrong understanding of std::setw (either as applying to all output until next std::setw occurs or maybe as setting tab stops).

std::setw, though, only applies to very next output parameter!

So std::cout << std::setw(11) << "E-ID" << emp_id; produces output as follows (newline here just indicating the separate output boundaries, periods symbolising spaces):

E-ID.......
77

Note how the string literal on its own is extended while the id then is appended afterwards!

What you instead want to have is rather something like:

std::cout << "E-ID " << std::setw(6) << emp_id;

which then produces

E_ID.
77....

The width of 6 is simply the desired total output width of 11 from which the length of the string literal (including the space) is subtracted.

Of course it is pretty inconvenient having to count string literal lengths manually. You could automate, though:

template <typename T>
class Tabbed
{
public:
    Tabbed(size_t width, std::string const& header, T const& data)
        : m_width(width), m_header(header), m_data(data)
    { }
private:
    size_t m_width;
    std::string const& m_header;
    T const& m_data;

    friend std::ostream& operator<<(std::ostream& s, Tabbed const& t)
    {
        return s << t.m_header << ' '
            << std::setw(t.m_width - t.m_header.length - 1) << t.m_data;
        // TODO: add a test to avoid subtraction yielding a negative value!
    }
};

This would allow for code like

std::cout << Tabbed(25, "Employee Id:", emp_id) << Tabbed(...) << Tabbed(...);

However it relies on class template argument deduction, thus C++ 17. If you happen to compile on an older standard then add a helper function analogous to std::make_pair for std::pairs.

Final note: The code is entirely untested, if you find a bug please fix yourself. Be aware that above code is intended only for the usage as shown! Then the Tabbed objects cannot outlive the the data they refer to. If you want to store the tabbing objects then you either need to make sure that the data referred to (apart from size) lives at least as long as the tabbing objects do – or you change the class to store copies of the data.

Aconcagua
  • 24,880
  • 4
  • 34
  • 59