How do stream manipulators work with arguments?

The Stroustrup C ++ book has an example of a user-defined manipulator that takes an argument (see the attached code). I am confused about how the structure is created. In particular, it looks like there are two int arguments for the smanip constructor, one for the ff function pointer, one for ii. I do not understand how the int argument is passed to create the structure using:

cout << setprecision(4) << angle; 

Also, what is the order in which these functions are called, and how are arguments of type Ch and Tr determined? Many thanks.

 // manipulator taking arguments struct smanip{ iso_base& (*f) (ios_base&, int); int i; smanip(ios_base& (*ff)(ios_base&, int), int ii) : f(ff), i(ii){} }; template<cladd Ch, class Tr> ostream<Ch, Tr>& operator<<(ostream<Ch, Tr>& os, smanip& m){ return mf(os, mi); } ios_base& set_precision(ios_base& s, int n){ return s.setprecision(n); // call the member function } inline smanip setprecision(int n){ return smanip(set_precision,n); } // usage: cout << setprecision(4) << angle; 
+6
source share
2 answers
 setprecision(4) 

causes

 inline smanip setprecision(int n){ return smanip(set_precision,n); } 

What creates smanip from a pointer to the set_precision and n functions.

 struct smanip{ ios_base& (*f) (ios_base&, int); int i; smanip(ios_base& (*ff)(ios_base&, int), int ii) : f(ff), i(ii){} }; 

smanip is a structure that contains a pointer to a function and an integer. This function takes ios_base by reference and int and returns ios_base by reference.

At this point, the line effectively looks like this:

 smanip m(&setprecision, 4); cout << m << (otherstuff); 

which matches this pattern:

 template<class Ch, class Tr> ostream<Ch, Tr>& operator<<(ostream<Ch, Tr>& os, smanip& m){ return mf(os, mi); } 

And the compiler can output Ch and Tr from the stream on the left side. In this case, std::cout . The code is executed by mf(os, mi) . This calls the function pointer held by smanip , passing it the stream and the integer held by smanip .

 ios_base& set_precision(ios_base& s, int n){ return s.setprecision(n); // call the member function } 

This calls cout.setprecision(n) .

Thus, the string is converted to:

 std::cout.setprecision(4) << angle; 
+6
source

The manipulator functor takes a pointer to a function and an int as arguments, and it stores it internally for later use. Designer signatures can be divided into two declarations for readability:

 typedef ios_base& (*f_ptr)(ios_base&,int); smanip( f_ptr f, int ) 

That is, the first argument is a pointer to a function, and the second is a value.

In order of execution, the setprecision function is called in the sample code first, this function saves the function pointer and value inside the smanip object and returns it. The object is passed to the corresponding operator<< , which extracts and executes a stored pointer to the function of the current thread that passes the argument.

 // on the calling end setprecision(4) // --> construct __s = smanip( set_precision, 4 ) (cout << ) // --> passes __s to `operator<<` // inside operator<< return mf( os, mi ); // calls: set_precision( os, 4 ) (mf == &set_precision // mi == 4 ) 
0
source

Source: https://habr.com/ru/post/900323/


All Articles