0

I am trying to format my output as:

1 [tab] First Name: John [tab] Last Name: Smith [tab] Age: 20 [tab]daysInCourse: {35, 40, 55} Degree Program: Security

My current code is:

{
    cout << left << setw(15) << studentID;
    cout << left << setw(15) << "First Name: " << FN;
    cout << left << setw(15) << "Last Name: " << LN;
    cout << left << setw(15) << "Email " << studentEmail;
    cout << left << setw(15) << "Age: " << age;
    cout << left << setw(15) << "{" << days[0] << ", " << days[1] << ", " << days[2];
    cout << left << setw(15) << "Degree Program: ";
}

I have played around with each row's setw value and cant seem to get it right. Does the setw function need to only be used with specific values?

Samuel Liew
  • 76,741
  • 107
  • 159
  • 260
  • `std::setw(...)` only applies to the next string-like object. So it will apply to '"First Name: "' but not `FN`. you need to invoke `std::setw(...)` for each string-like object. You only need to call `std::left` once per output stream, though. – JohnFilleau Mar 02 '20 at 02:17

1 Answers1

1

As mentioned in comments, the setw manipulator only applies to the next string, so

cout << left << setw(15) << "{" << days[0] << ", " << days[1] << ", " << days[2];

will set a width of 15 only for the character { (similarly in the line with "First Name: ", etc.). It is also worth noting that if a string exceeds the specified width, then it will push the next contents and break the alignment of your columns; so you need to set the width thinking about the largest possible contents.

Here is a working example to implement what you want, using a stringstream to form the string before printing it (in order for setw to apply to the entire thing):

#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
#include <vector>

// ------------------------------------------------------------------------

struct Student 
{
    std::string ID, First, Last, Email, Degree;
    unsigned age;
    std::vector<unsigned> days;

    Student( std::string ID, std::string First, std::string Last, unsigned age, 
        std::string Email, std::string Degree, std::vector<unsigned> days ) 
    : ID(ID), First(First), Last(Last), age(age), Email(Email), Degree(Degree), days(days)
    {}
};

std::ostream& operator<< ( std::ostream& os, const Student& s ) {
    std::ostringstream ss;

    ss << "First Name: " << s.First;
    os << std::left << std::setw(25) << ss.str();
    ss.str("");

    ss << "Last Name: " << s.Last;
    os << std::left << std::setw(35) << ss.str();
    ss.str("");

    ss << "Email: " << s.Email;
    os << std::left << std::setw(50) << ss.str();
    ss.str("");

    ss << "Age: " << s.age;
    os << std::left << std::setw(10) << ss.str();
    ss.str("");

    ss << "{" << s.days.at(0) << ", " << s.days.at(1) << ", " << s.days.at(2) << "}";
    os << std::left << std::setw(20) << ss.str();
    ss.str("");

    ss << "Degree Program: " << s.Degree;
    os << std::left << std::setw(30) << ss.str();
    ss.str("");

    return os << std::endl;
}

// ------------------------------------------------------------------------

int main() {
    std::cout << Student("A3","Robert","Smith",19,"example@foo.com","SOFTWARE",{20,40,33});
    std::cout << Student("A4","Alice","Smith",22,"example@bar.net","SECURITY",{50,58,40});
}

outputs:

First Name: Robert       Last Name: Smith                   Email: example@foo.com                            Age: 19   {20, 40, 33}        Degree Program: SOFTWARE      
First Name: Alice        Last Name: Smith                   Email: example@bar.net                            Age: 22   {50, 58, 40}        Degree Program: SECURITY 

Note that I have set different widths for each field, depending on the expected lengths of the contents. For example, e-mail addresses can be quite long, but the age will rarely exceed two digits.

underscore_d
  • 6,309
  • 3
  • 38
  • 64
Jonathan H
  • 7,591
  • 5
  • 47
  • 80