Overloading >>

Im trying to overload the >> operator, so that if someone enters "2018/8/18" as the input, my overloaded operator will disassemble the input and change values in my class appropriately.

My class:
1
2
3
4
5
class Date {
		int year;
		short month;
		short day;
}


My attempt at overloading << operator :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
	std::ostream& operator<<(std::ostream& out, const Date& date) {
		if (10 > date.day) {
			out << date.year << "/" << date.month << "/0" << date.day;
		}
		else if (date.month > 10) {
			out << date.year << "/0" << date.month << "/" << date.day;
		}
		else if (10 > date.day && 10 > date.month) {
			out << date.year << "/0" << date.month << "/0" << date.day;
		}
		else {
			out << date.year << "/" << date.month << "/" << date.day;
		}
		return out;
	}


And here is where Im stuck, overloading >>

1
2
3
	std::istream& operator>>(std::istream& in, const Date& date) {
                //what to do?
	}
Last edited on
1
2
3
4
5
std::istream& operator>>(std::istream& in, /*const*/ Date& date) {
   char drop_it
   in >> date.year >> drop_it >> date.month >> drop_it >> date.day;
   return in;
}
may also use std::istream::ignore http://www.cplusplus.com/reference/istream/istream/ignore/
no `const', you intend to modify the object.

By the way, you do not properly handle single digits in both day and month.
Test the output with 1944/6/6
Last edited on
I dont understand, are you declaring drop_it as a char?

Also, is it because the order is incorrect?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
	std::ostream& operator<<(std::ostream& out, const Date& date) {
		if (10 > date.day && 10 > date.month) {
			out << date.year << "/0" << date.month << "/0" << date.day;
		}
		else if (10 > date.day) {
			out << date.year << "/" << date.month << "/0" << date.day;
		}
		else if (10 > date.month) {
			out << date.year << "/0" << date.month << "/" << date.day;
		}
		else {
			out << date.year << "/" << date.month << "/" << date.day;
		}
		return out;
	}
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>
#include <iomanip>

struct Date {

    int year = 1900 ;
    int month = 1 ;
    int day = 1 ;
};

std::ostream& operator<< ( std::ostream& stm, const Date& dt ) {

    const char old_fill = stm.fill() ;

    return stm << std::setfill('0') << std::setw(4) << dt.year << '/' << std::setw(2)
               << dt.month << '/' << std::setw(2) << dt.day << std::setfill(old_fill) ;
}

// extract the next next non white space character in the stream
// return true if it is the expected separator '/', false otherwise
static bool valid_sep( std::istream& stm ) {

    char separator ; // expected to be '/'
    return stm >> separator && separator == '/' ;
}

std::istream& operator>> ( std::istream& stm, Date& dt ) {

    int y, m, d ;
    // if the input is of the form year/month/date ie. five fields
    // year, '/', month, '/', day (white space is allowed between fields)
    if( stm >> y && valid_sep(stm) && stm >> m && valid_sep(stm) && stm >> d )
        dt = { y, m, d } ; // update dt with the values that were read
    // else leave dt unchanged

    return stm ;
}

int main()
{
    Date dt { 2000, 6, 9 };
    std::cout << dt << '\n' ;

    std::cin >> dt ;
    std::cout << dt << '\n' ;
}

http://coliru.stacked-crooked.com/a/586e3048f28a988d
JLBorges, what if I want to check for validation within the >> overload? Here is my attempt:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
	std::istream& operator>>(std::istream& in, Date& date) {

		int y, m, d;
		//checking form of input, white spaces allowed
		if (in >> y && validSep(in) && in >> m && validSep(in) && in >> d) {
			if (date.inRangeYear(y) && date.inRangeMonth(m) && date.inRangeDay(d)) {
				date = { y, m, d };
			}
			else if (!date.inRangeYear(y) && date.inRangeMonth(m) && date.inRangeDay(d)) {
				date.error = YEAR_ERROR;
			}
			else if (date.inRangeYear(y) && !date.inRangeMonth(m) && date.inRangeDay(d)) {
				date.error = MON_ERROR;
			}
			else if (date.inRangeYear(y) && date.inRangeMonth(m) && !date.inRangeDay(d)) {
				date.error = DAY_ERROR;
			}
		}
		else {
			date.error = CIN_FAILED;
			}

			return in;
		}




And my inRange functions are:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
	bool Date::inRangeYear(int yy) const {
		return (2000 <= yy && 2030 >= yy) ? true : false;
	}

	bool Date::inRangeMonth(int mm) const {
		return (1 <= mm && 12 >= mm) ? true : false;
	}

	bool Date::inRangeDay(int dd) const {
		if (month == 2) {
			//leap year rules
			if ((year % 4 == 0) && (year % 100 == 0) && (year % 400 == 0)) {
				return (1 <= dd && 29 >= dd) ? true : false;
			}
			else {
				return (1 <= dd && 28 >= dd) ? true : false;
			}
		}
		if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) {
			return (1 <= dd && 31 >= dd) ? true : false;
		}
		else if (month == 4 || month == 6 || month == 9 || month == 11) {
			return (1 <= dd && 30 >= dd) ? true : false;
		}
	}


Is this a valid way to achieve this? Because when Im testing, it seems to fail at the day. If my input is 2000/1/50, it doesnt seems to enter the else if statement on line 15 of the operator>> bit.
Last edited on
> I also have int errState, and if a string such as 'abcd' is the input,
> I should leave everything unchanged and set errState to 1 (for CIN_ERROR).

This is delightfully bizarre.

Why does this particular career teacher believe that the canonical way of detecting input failure by checking the state of the stream after attempted input is inadequate?

In any case, here goes!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <iostream>
#include <iomanip>

struct Date {

    enum error_t { NO_ERROR = 0, INPUT_ERROR = 1, YEAR_ERROR = 2, MONTH_ERROR = 3, DAY_ERROR = 4 };

    int year = 1900 ;
    int month = 1 ;
    int day = 1 ;

    error_t errState = NO_ERROR ;

    static error_t validate( int y, int m, int d )
    {
        // TO DO:
        // return YEAR_ERROR if y is invalid
        // return MONTH_ERROR if m is invalid
        // return DAY_ERROR if d is invalid

        return NO_ERROR ; // if y, m, d form a valid date
    }
};

std::ostream& operator<< ( std::ostream& stm, const Date& dt ) {

    if( dt.errState == Date::NO_ERROR ) {

        const char old_fill = stm.fill() ;

        return stm << std::setfill('0') << std::setw(4) << dt.year << '/' << std::setw(2)
                   << dt.month << '/' << std::setw(2) << dt.day << std::setfill(old_fill) ;
    }

    else return stm << "<invalid date>" ;
}

// extract the next next non white space character in the stream
// return true if it is the expected separator '/', false otherwise
static bool valid_sep( std::istream& stm ) {

    char separator ; // expected to be '/'
    return stm >> separator && separator == '/' ;
}

std::istream& operator>> ( std::istream& stm, Date& dt ) {

    int y, m, d ;
    // if the input is of the form year/month/date ie. five fields
    // year, '/', month, '/', day (white space is allowed between fields)
    if( stm >> y && valid_sep(stm) && stm >> m && valid_sep(stm) && stm >> d ) {

        const Date::error_t state = Date::validate( y, m, d ) ;
        if( state == Date::NO_ERROR ) dt = { y, m, d, state } ; // update dt with the values that were read
        else dt.errState = state ; // update only error state; leave everything else unchanged
    }

    // otherwise, update error state; leave everything else unchanged
    else dt.errState = Date::INPUT_ERROR ;

    return stm ;
}
1
2
			if (date.inRangeYear(y) && date.inRangeMonth(m) && date.inRangeDay(d)) {
				date = { y, m, d };

when you check day validity you need to use the month and year too.
in Date::inRangeDay() you are using the month and year of your object, not the values that were inputted by the user.

1
2
3
4
5
6
7
	bool Date::inRangeDay(int dd) const {
		if (this->month == 2) {


	bool Date::inRangeDay(int dd, int mm, int yy) const {
	//this wouldn't use or modify any state of the object, ¿why is it a member function?
			if (mm == 2) {

Topic archived. No new replies allowed.