- Built-in Manipulators
- Custom Manipulators for User-Defined Objects
- User-Defined Inserters and Extractors
User-Defined Inserters and Extractors
When these manipulators are inserted into an ostream object, they set the user-defined flags that can then be used by the user-defined inserter or extractor. Listing 5 demonstrates how a user-defined inserter would access user-defined flags:
Listing 5 Defining an Inserter That Accesses a User-Defined Flag When Formatting for Time
ostream &operator<<(ostream &Out,course &X) { if(Out.iword(UserFlag["TimeFormat"]) == MilitaryTime){ Out << X.StartTime.c_str(); } if(Out.iword(UserFlag["TimeFormat"]) == WallClockTime){ int SomeTime = atoi(X.StartTime.c_str()); strstream Buffer; string NewTime; if(SomeTime <= 1200){ Buffer << SomeTime << ends; Buffer >> NewTime; if(SomeTime >= 1000){ NewTime.insert(2,":"); } else{ NewTime.insert(1,":"); } Out << NewTime.c_str() << " a.m." << endl; } else{ SomeTime = SomeTime - 1200; Buffer << SomeTime << ends; Buffer >> NewTime; NewTime.insert(1,":"); Out << NewTime.c_str() << " p.m." << endl; } } return(Out); }
The inserter defined in Listing 5 determines how to print out a course time depending on how the user-defined flags are set.
Listing 5 demonstrates how a single flag can be used with user-defined inserters. Because we've stored the flags in a map container, any number of user-defined flags can be accessed in the inserters and extractors to determine how the object should be translated, as shown in Listing 6.
Listing 6 Defining an Inserter That Utilizes the Map Container To Store User-Defined Flags
ostream &operator<<(ostream &Out,course &X) { if(Out.iword(UserFlag["TimeFormat"]) == MilitaryTime){ ... // military time processing ... } if(Out.iword(UserFlag["HornClause"]) == HClause){ Out << toHornClause() // Horn Clause processing } if(Out.iword(UserFlag[SomeUserDefinedFlag]) == FlagValue){ // Specialized processing } return(Out); }
Once the inserters, extractors, and manipulators for the user-defined class have been written, we can combine our customized stream processing with the algorithms and containers. The ostream_iterator and istream_iterator class serves as the glue between the iostreams, algorithms, and container classes, as shown in Listing 7:
Listing 7 Using an ostream Iterator and the copy Algorithm To Send a Vector of User-Defined Objects to a Printer
... int main(int argc,char *argv[]) { ... ofstream DegreePlan(open("/dev/lp0",O_WRONLY)); vector<course> Schedule; course Course; ... DegreePlan << hornClause << clockTime; ostream_iterator<course> Out(DegreePlan,"\n"); copy(Schedule.begin(),Schedule.end(),Out); ... }
Listing 7 uses the copy algorithm to send our Schedule object to a printer. We've constructed an ofstream object and connected to a printer named /dev/lp0. We've set our user-defined flags with the hornClause and clockTime manipulators. The ostream_iterator is constructed with our ofstream object. We then can use the copy algorithm to send our course objects (represented as horn clauses) to the printer.
How does this work? The ostream_iterator and istream_iterators will ultimately cause the user-defined inserters and extractors to be called. That topic will be discussed in our next article.