Monday, December 9, 2024

IO Stream extraction and insertion operators and Manipulators

Overview
istreams defines extraction operators that are basically overloaded operator >>() functions to extract values from the inputs. Similarly, ostreams defines insertion operators that are basically overloaded operator<<() functions to insert values into the output.
Manipulators are helper functions that prepare the input/output streams before using operator << or operator >>.

Details

operator >>()
The istream base class has overloaded operator >> to receive input from different sources such as console, character buffers, and files. The target for the input can be a char, bool, int or even a string.
The overloaded operator >> which is applied to an input stream is known as extraction operator. It is overloaded for following data types. User defined classes and other std library data types such as basic_string, provide their own overloaded operator >> methods.
Before parsing a sentry object is created to check for errors and parsing white spaces. It's later checked, and if returns false the function will return. Otherwise it will continue to process the input.

Arithmetic types
syntax
istream& operator>> (xxxxx& val)
where xxxxx can be any of the data types listed below. 

boolvoid* short  unsigned short
int unsigned int long unsigned long
long long unsigned long long float double
long double

Starting with C++11, it's possible to receive formatted input  of currency and date and time using  << operators. Also the function calls num_get::get () from the num_get facet from the local or imbued locale to parse and extract the arithmetic value.
Example
    istringstream src ("10");
    int i;
    src >> i;
    //prints 10
    cout  << i;

streambuf
syntax
istream& operator>> (streambuf* sb )
This is an unformatted input. 
First it constructs the sentry object and completes the preliminary checks and actions.
Later it extracts as many characters as possible from the stream buffer and inserts them into the output sequence controlled by the stream buffer object pointed by sb (if any), until either the input sequence is exhausted or the function fails to insert into the object pointed by sb.
Example
    istringstream src ("   hello, world! ");
    //prints:"hello, world! "
    cout << '"'; src >> cout.rdbuf(); cout << '"';

manipulators
syntax
istream& operator>> (istream& (*pf)(istream&))
istream& operator>> (ios& (*pf)(ios&))
istream& operator>> (ios_base& (*pf)(ios_base&))
Calls pf(*this), where pf may be a manipulator.
Manipulators are functions specifically designed to be called when used with this operator.
This operation has no effect on the input sequence and extracts no characters (unless the manipulator itself does, like ws).

The following manipulators defined for istream. These are  discussed in detail below. 
wsboolalpha
noboolalpha
skipws
noskipws
dec
hex
oct
setbasesetiosflags
resetiosflags

operator << ()
The ostream base class has overloaded operator << to print on different targets such as console, character buffers, and files. The source for output can be a char, bool, int or even a string.

The ostream base classes  implement the overloaded operator << which is applied to an output stream is known as extraction operator. It is overloaded for following data types.User defined classes and other std library data types such as basic_string, provide their own overloaded << methods.
Before parsing a sentry object is created to check for errors. It's later checked, and if returns false the function will return. Otherwise it will continue to process the input.
Starting with C++11, it's possible to print formatted output of currency and date and time using << operators.

Arithmetic types
syntax
ostream& operator<< (xxxxx val)
where xxxxx can be any of the data types listed above for operator >> arithmetic types. 
The function calls num_get::put() from the num_put facet from the local or imbued locale to parse and extract the arithmetic value.
Example
    int i{10};
    //prints 10
    cout  << i;

streambuf
syntax
ostream& operator<< (streambuf* sb )
This is an unformatted output. 
First it constructs the sentry object and completes the preliminary checks and actions.
Later it extracts as many characters as possible from the stream buffer sb (if any) and inserts them into  the stream, until either the input sequence is exhausted or the function fails to insert into the object pointed by sb.
Example
    istringstream src ("   hello, world! ");   
    //prints:"   hello, world! "
    cout << '"' << src.rdbuf() << '"';

manipulators
syntax
ostream& operator>> (ostream& (*pf)(ostream&))
ostream& operator>> (ios& (*pf)(ios&))
ostream& operator>> (ios_base& (*pf)(ios_base&))

Calls pf(*this), where pf may be a manipulator.
Manipulators are functions specifically designed to be called when used with this operator.
This operation has no effect on the output sequence and inserts no characters (unless the manipulator itself does, like endl).

The following manipulators defined for ostream. These are discussed in detail below.
endl endsflush 
boolalpha
noboolalpha
showbase
noshowbase
showpoint  
noshowpoint 
showpos  
noshowpos 
unitbuf 
nounitbuf 
uppercase 
nouppercase 
dec
hex
oct
fixed
scientific
hexfloat 
defaultfloat 
internal
left
right
setfill 
setbasesetiosflags
resetiosflags
setprecision 
setw 


user defined class stream manipulators
As discussed above, The operator >> and operator << can be extended to user defined classes as well.

The following Example 3 demonstrates implementation of custom <<  and  >> operators for a rect structure. The usage example below creates a rect structure and accepts inputs for height and width using a custom >> operator and later print them to console using a custom << operator as seen in its console output.

struct rect
{
    int  h,w;
};

ostream& operator<<(ostream& os,  rect& r)
{
    ostream::sentry s(os);
    if (s) 
        os << r.h << " " << r.w << endl;
    return os;
}
istream& operator>>(istream& is,  rect& r)
{
    istream::sentry s(is);
    if (s) 
        is >> r.h >> r.w;

    return is;
}
istringstream ss{" 10 20"}; rect r; //creates rect{10,20} ss >> r; //prints:10 20 cout << r;

Stream input and output manipulators
Stream manipulators are defined for formatted output. Some of these can be applied to Input streams, Output streams or Both.
Internally they call setf  and unsetf functions to set or adjust formatting options. The default behavior is same as the formatting bitset flags as discussed in ios_base class.

These can be grouped into two groups - Nonparametric and Parametric.

 NonParametric Manipulators
ManipulatorDescription
boolalpha

noboolalpha
Toggles between textual or numeric representation for boolean values while reading writing. 

Example
istringstream is{"1 0 true false"};
bool b{false}, b2{false};

//b:true b2:false
is >> noboolalpha >> b >> b2;
//prints true false
cout << boolalpha << b << " " << b2 << endl;

//b:true b2:false
is >> boolalpha >> b >> b2;
//prints 1 0
cout << noboolalpha << b << " " << b2 << endl;
showpos

noshowpos
Toggles printing positive sign for positive numbers.

Example
//prints +1 -1
cout << showpos << 1 << " " << -1  << endl;

//prints 1 -1
cout << noshowpos << 1 << " " << -1  << endl;
uppercase

nouppercase
Toggles between writing uppercase or lowercase letters for numeric values.

Example
cout << showbase << hex;
//prints 0x50
cout << nouppercase << 80 << endl;
//prints 0x50
cout << uppercase << 80 << endl;
oct

dec

hex
Reads and writes integral values octal or decimal or hex.

Example
istringstream ss{"0x90 100 027"};
int i, i2, i3;

//i:144 i2:100 i3:027
ss >>  hex >> i >> dec >> i2 >> oct >> i3;

//prints 144 100 23
cout << i << " " << i2 << " " << i3 << endl;

//prints 90 100 027
cout << hex << i << " " << dec << i2 << " " << oct << i3 << endl;
showbase

noshowbase
Toggles between printing of prefix for numeric base of numeric values.

Example
//prints 90 100 27
cout << noshowbase << hex << 144 << " " << dec << 100 << " " << oct << 23 << endl;

//prints 0x90 100 027
cout << showbase << hex << 144 << " " << dec << 100 << " " << oct << 23 << endl;
showpoint

noshowpoint
Toggles between printing of the decimal point for floating-point values.

Example
//prints 12 12.34
cout << noshowpoint << 12.0 << " " << 12.34 << endl;

//prints 12.0000 12.3400
cout << showpoint << 12.0 << " " << 12.34 << endl;
skipws

noskipws
Toggles between Skipping leading whitespaces for formatted inputs with operator  >>.

Example
istringstream ss ("hello world!");
string s, s2;
    
//s:"hello"  s2:"world!"
ss >> skipws >> s >> s2;

ss.clear();
ss.seekg(0, ios::beg);

//s:"hello"  s2:""
ss >> noskipws >> s >> s2;
unitbuf

nounitbuf
Toggles between Flushing the output buffer after each write operation  for streams such as cerr and wcerr.

Example
void print(bool b)
{
    cout << "start" << endl;
    cerr  << ((b)?unitbuf:nounitbuf) << "ondu\n";
    cout << "stop" << endl;
    this_thread::sleep_for(2000ms);
}

cerr.sync_with_stdio(false);
/*prints on coliru 
start
ondu
stop
*/
print(true);

/*prints
start
stop
ondu
*/
print(false);
left

right

internal
left: fills with fill characters to the right.
right: fills with fill characters to the left.
internal: adds fill characters to the internal designated point.

Example
//prints:$$$$$$1234
cout << setw(10) << setfill('$') << internal << 1234  << endl;

//prints:1234$$$$$$
cout << setw(10) << setfill('$') << left << 1234 << endl;

//prints:$$$$$$1234
cout << setw(10) << setfill('$') <<  right << 1234 << endl;
fixed

scientific

hexfloat

defaultfloat
Uses decimal/scientific/hexadecimal scientific/normal notation for floating-point values.

Example
//prints:1234.56
cout << setprecision(2) << fixed << 1234.56 << endl;

//prints:1.23e+03
cout << scientific << 1234.56 << endl;

//prints:0x1.34a3d70a3d70ap+10
cout << hexfloat << 1234.56  << endl;

//prints:1.2e+03
cout << defaultfloat << 1234.56  << endl;
endlWrites a newline character and flushes the output.

Example
/*prints
ondu
eradu

*/
cout << ondu << endl << eradu << endl;
endsWrites a string terminating character (\0). It's meant to be used with deprecated strstream object.
flushFlushes the output.

Example
ostream& delay(ostream& os)
{
    this_thread::sleep_for(200ms);
    clog << "stop\n";

    return os;
}

void test(bool b)
{
    clog << "start\n";
    if (b)
        cout << "hello\n" << flush <<  delay << "world" << endl;    
    else
        cout << "hello\n" <<  delay << "world" << endl;    
}

    /*prints
    start
    hello
    stop
    world
    */
    test(true);

    this_thread::sleep_for(500ms);

    /*prints
    start
    stop
    hello
    world
    */
    test(false);
wsReads and ignores whitespaces during unformatted Inputs.

Example
string a, b, c;
istringstream iss ("one \n \n \n two");
    
//a:"one"
getline(iss,a);

//b:""
getline(iss,b);
    
//c:"two"
getline(iss>>ws,c);

Parametric Manipulators
ManipulatorDescription
setiosflags (ios_base::fmtflags mask)

resetiosflags (ios_base::fmtflags mask)
Sets or resets mask as format flag similar to setf() or unsetf().

Example
    cout << hex << setiosflags (ios::showbase);
    
    //prints 0x64
    cout << 100 << endl;

    //prints 64
    cout << resetiosflags(ios::showbase) << 100 << endl;
setw (int n)Sets the field width of the next input and output to n.

Example
//prints:$$$$$$1234
cout << setw(10) << setfill('$') << 1234  << endl;
setfill (char_type c)Defines c as the fill character.

Example
//prints:$$$$$$1234
cout << setw(10) << setfill('$') << 1234  << endl;
setprecision (int n)Sets n as the new value for the precision of floating-point values.

Example
//prints:1234.56
cout << setprecision(2) << fixed << 1234.56 << endl;
/*unspecified*/ get_time
(struct tm* tmb, const charT* fmt)

/*unspecified*/ put_time 
(struct tm* tmb, const charT* fmt)
Reads or Writes a date/time value according to the format.

Example
    tm t = {};
    istringstream ss("2018-September-21 11:58:00");
    ss.imbue(locale("en_US.UTF8"));
    
    //t:1537531080
    ss >> get_time(&t, "%Y-%b-%d %H:%M:%S");
    
    //prints:Fri Sep 21 11:58:00 2018
    cout << std::put_time(&t, "%c") << endl;
/*unspecified*/ get_money
MoneyT& mon, bool intl = false )

/*unspecified*/ put_money
const MoneyT& mon, bool intl = false )
Reads or Writes a monetary value using the local currency symbol or intl.

Example
    long double v, v2;
    std::string v3;

    istringstream in("$1,234.56 2.22 USD  3.33");
    in.imbue(locale("en_US.UTF-8"));
    //v:123456 v2:222, v3:333
    in >> get_money(v) >> get_money(v2) >> get_money(v3, true);
    
    cout.imbue(locale("en_US.UTF-8"));
    /* prints: 
       $12.34 
       USD  12.34
    */
    cout << showbase << put_money(1234) << endl
         << put_money(1234, true) << endl;
/*unspecified*/ quoted 
(const T* s,d = T('"'), T  = T('\\') )
Allows insertion and extraction of quoted strings, such as the ones found in CSV or XML.

Example
    string in[] {"Vedavyas", "\"Mako\"", "Rao"};
    stringstream ss;
    string out[3];

    //Without Quoted
    
    //ss:Vedavyas"Mako"Rao;
    ss << in[0] << in[1] << in[2];

    //out[0]:"Vedavyas"Mako"Rao"
    ss >> out[0];
    

    //With Quoted
   
    ss.clear();
    ss.str("");
    
    //ss:"Vedavyas""\"Mako\"""Rao";
    ss << quoted(in[0])  << quoted(in[1]) << quoted(in[2]);

    //out[0]:"Vedavyas" out[1]:"\"Mako\"" out[2]:"Rao"
    ss >> quoted(out[0]) >> quoted(out[1]) >> quoted(out[2]);

    in[1] = "$Mako$";

    //With Quoted custom delimiters

ss.clear(); ss.str(""); //ss:$Vedavyas$$%$Mako%$$$Rao$; ss << quoted(in[0], '$', '%') << quoted(in[1], '$', '%') << quoted(in[2], '$', '%'); //out[0]:"Vedavyas" out[1]:"$Mako$" out[2]:"Rao" ss >> quoted(out[0], '$', '%') >> quoted(out[0], '$', '%') >> quoted(out[2], '$', '%');

The example 4 demonstrates usage of ostream manipulators.
The example 5 demonstrates usage of istream manipulators.

Custom Manipulator
Further they can be extended with user defined manipulators. 
This  example 6 below defines a custom ostream manipulator called beep to alert the user by making beep sound. 
#ifdef WINDOWS
#include <Windows.h>
void beep() 
{
    Beep(523, 800);
}
#elif LINUX
#include <stdio.h>
void beep() 
{
    system("echo -e "\007" >/dev/tty10");
}
#else
#include <stdio.h>
void beep() 
{
    cout << "\a" << flush;
}
#endif

std::ostream& beep(std::ostream &os)
{
    beep();
    return os;
}

clog << "Warning" << beep << endl;



No comments:

Post a Comment