C ++ resentment Note 7 -- function Adapter
Write a general counting function testcount and use it to count the number of spaces in the string:
#include <string>#include <iostream>using namespace std;bool TestIsspace( wchar_t ch ){ if ( ch == ' ' ) return true; else return false;}template <class T, class Fn >int TestCount( T p1, T p2, Fn pFn ){ int ret = 0; for (; p1 != p2; p1 ++ ) if ( pFn(*p1) ) ret++; return ret;}void main(){ wstring s = L" hel lo "; wchar_t buf[] = L" hel lo "; cout << TestCount(s.begin(), s.end(), TestIsspace ) << endl; cout << TestCount(buf, buf+wcslen(buf), TestIsspace ) << endl;}
Use testcount to count the number of non-space characters. You may want to write another testisspaceneg, which calls testisspace to return the result.
bool TestIsspaceNeg( wchar_t ch ){ return !TestIsspace( ch );}
If testisspaceneg is passed in as the third parameter of testcount, isn't it all done? Although this method is very effective, it is not cumbersome. Functions similar to testisspace are more frequently used, such as library functions such as isspace, isalpha, and isdigit. Do they need to be "overwritten" every time a population is obtained? Is there a general method to retrieve the return values of each function and return them? Function pointer! In this way, you can manage a function with the same function signature. No.
bool TestGenericNeg( bool (*pFn)(wchar_t), wchar_t ch ){ return !pFn(ch);}
To generate the antifunction of testisspace, just throw the function pointer to testgenericneg.
Testgenericneg (testisspace, CH );
Well, this is an improvement. Both testisspace and library functions can be used, as long as the function signature is bool () (wchar_t. But have you found that there are more than one testgenericneg parameter, and two parameters are indispensable: one is the original function, and the other is the parameter of the original function. It is obviously not acceptable to only give testgenericneg to testcount. You must specify the function used for testgenericneg. Only testgenericneg function pointers do not work, and its information is too limited. This is also a fatal defect of function pointers. The solution to this defect is to use a function object, that is, to use a class that overload the call operator (that is, parentheses. Class Object can carry more information, including the original function pointer.
# Include <string ># include <iostream> using namespace STD; bool testisspace (wchar_t ch) {If (CH = '') return true; else return false ;} template <class T, class FN> int testcount (T P1, t P2, FN PFn) {int ret = 0; For (; P1! = P2; P1 ++) if (PFN (* P1) RET ++; return ret;} // used for other functions. The template <class FN, class T> class negclxenclose {public: fn pfn; negclxenclose (FN PFn) {This-> PFN = PFN;} bool operator () (T ch) {return! This-> PFN (CH) ;}}; void main () {wstring S = l "hello"; negclxenclose <bool (*) (wchar_t ), wchar_t> negobj (testisspace); cout <testcount (S. begin (), S. end (), negobj) <Endl; cout <testcount (S. begin (), S. end (), negclxenclose <bool (*) (wchar_t), wchar_t> (testisspace) <Endl; // For convenience, use a temporary object}
At this time, we have achieved our goal. negclxenclose is a universal and qualified anti-decoder. However, we found that when using it, we had to manually fill in the data type, such as <bool (*) (wchar_t) and wchar_t> above, which was too troublesome and a little imperfect. Is there any way for the compiler to help us fill in? The answer is: yes, a function template. When we call a function template, just like calling a common function, we never need to manually fill in the data type. This job is done by the compiler. So we can use this.
The final code can be written as follows:
# Include <string ># include <iostream> using namespace STD; bool testisspace (wchar_t ch) {If (CH = '') return true; else return false ;} template <class T, class FN> int testcount (T P1, t P2, FN PFn) {int ret = 0; For (; P1! = P2; P1 ++) if (PFN (* P1) RET ++; return ret;} template <class FN, class T> class negclxenclose {public: fn pfn; negclxenclose (FN PFn) {This-> PFN = PFN;} bool operator () (T ch) {return! This-> PFN (CH) ;}}; template <class ret, class T> negclxenclose <RET (*) (T), T> improvefn (Ret (* PFn) (t) {return negclxenclose <ERT (*) (T), T> (PFn);} void main () {wstring S = l "hello "; cout <testcount (S. begin (), S. end (), improvefn (testisspace) <Endl; // is it concise}
Is it brilliant? In fact, these tools already exist in the C ++ standard library! This is the function adapter adaptor. The following code is implemented using the Standard Library:
#include <string>#include <iostream>#include <functional> //for not1using namespace std;bool TestIsspace( wchar_t ch ){ if ( ch == ' ' ) return true; else return false;}template <class T, class Fn >int TestCount( T p1, T p2, Fn pFn ){ int ret = 0; for (; p1 != p2; p1 ++ ) if ( pFn(*p1) ) ret++; return ret;}void main(){ wstring s = L" hel lo "; cout << TestCount(s.begin(), s.end(), not1( ptr_fun(TestIsspace)) ) << endl;}
The difference is that not1 receives a function object instead of a function pointer, so we need to use ptr_fun to convert testisspace.