C + + -- function object

Many STL algorithms use function objects - also known as function symbols. A function character is any object that can be used in conjunction with () in a functional manner. Including function name, function pointer and class object of overload ().

For example, such a class is the function symbol

class A
{
private:
    int a;
public:
    A(int x = 20) : a(x) {}
    int operator() (int b)
    {
        return a + b;
    }
};
int main()
{
    A temp;
    cout << temp(10);
    return 0;
}

Operation results

For based on function symbol_ each,for_ The third parameter of each can accept the function pointer, but the generality is not strong. In order to improve the generality, you can pass in the template as the function symbol.

Using template function

void show(const T & t)
{
    cout << t << " ";
}
int main()
{
    int num[] = {5,2,1,3,6,9,8,7,20,10};
    list <int> ls(num,num+10);
    //ostream_iterator<int,char> out (cout," ");
    for_each(ls.begin(), ls.end(),show<int>);
    return 0;
}

You can do this by using template classes

template <typename T>
class show
{
public:
    void operator()(T & t)
    {
        cout << t << " ";
    }
};
int main()
{
    int num[] = {5,2,1,3,6,9,8,7,20,10};
    list <int> ls(num,num+10);
    //ostream_iterator<int,char> out (cout," ");
    for_each(ls.begin(), ls.end(),show<int>());
    return 0;
}

Operation results

STL defines the concept of function symbols

Generator: a function that can be called without parameters

Unary function: a function that can be called with one parameter

Binary function: a function that can be called with two parameters

Further

Predicate: the return value is a unary function of bool

Binary predicate: binary function whose return value is bool

You can change a template function that accepts two parameters into a template class that accepts one parameter (overload ()).

for example

template<typename T>
void show(const T & t,int a) {
    cout << t + a << " ";
}
int main()
{
    list <int> ls = {1,2,3,4,5,6,7,8,9,};
    for(auto i = ls.begin();i!=ls.end();i++){
        show(*(i),10);
    }
    return 0;
}

Become

template<typename T>
class show
{
private:
    T a;
public:
    show(const T & x) : a(x) {}
    void operator()(const T & t)
    {
        cout << t + a << " ";
    }
};
int main()
{
    show<int> s(10);
    list <int> ls = {1,2,3,4,5,6,7,8,9,};
    for(auto i = ls.begin();i!=ls.end();i++){
        s(*(i));
    }
    cout << endl;
    //or
    for_each(ls.begin(), ls.end(),show<int>(5));
    return 0;
}

Operation results

Some function symbols predetermined by C + +

For example, transform() -- it has two versions

The first version accepts four parameters. The first two parameters are iterators, representing intervals. The third parameter is an iterator pointing to where to copy. The last parameter is a function symbol, which is applied to each element.

For example, find the square root of each number and copy it to the output stream

int main()
{
    list <int> ls = {1,2,3,4,5,6,7,8,9,};
    ostream_iterator<double,char> out(cout, " ");
    transform(ls.begin(),ls.end(),out,sqrt<int>);
    return 0;
}

The second version jieshou has five parameters. The first two are the same as above. The third represents the starting position of the second container, the fourth represents the iterator pointing to where to copy, and the fifth is a binary function symbol, which is applied to every two elements.

For example, sum every two elements of two containers and copy them to the output stream

template <typename T>
T add(T & t1, T & t2)
{
    return t1 + t2;
}
int main()
{
    //C + + predetermined function symbol sqrt
    list <int> ls = {1,2,3,4,5,6,7,8,9,};
    list <int> ls1 = {9,8,7,6,5,4,3,2,1};
    ostream_iterator<int,char> out(cout, " ");
    transform(ls.begin(),ls.end(),ls1.begin(),out,add<int>);
    return 0;
}

Operation results

The header file < functional > defines many similar template function symbols.

#include <functional>
+       plus
-       minus
*       multiplies
/       divides
%       modulus
-       negate
==      equal_to
!=      not_equal_to
>       greater
<       less
>=      greater_equal
<=      less_equal
&&      logical_and
||      logical_or
!       logical_not

Note that they are essentially class es, only overloaded () to behave like functions.  

Adaptive function operators and function adapters

Adaptive is the process of automatically adjusting the processing method, processing sequence, processing parameters, boundary conditions or constraints according to the data characteristics of the processed data in the process of processing and analysis, so as to adapt it to the statistical distribution characteristics and structural characteristics of the processed data, so as to obtain the best processing effect.

STL has five related concepts

Adaptive generator

Adaptive univariate function

Adaptive binary function

Adaptive predicate

Adaptive binary predicate

The reason for making the function symbol adaptive is that it carries typedef members that identify the parameter type and return type. These members are

result_type, first_argument_type, second_argument_type.

The meaning of function character self adaptability is that the function adapter object {can use the function object and consider that there are members of these typedef s. For example, a function that accepts an adaptive function operator parameter can use result_type member to declare a variable that matches the return type of the function.

STL provides function adapter classes that use only these tools

Suppose you want to add all the elements x2 in the container, you can use the binary function multiples, or you can use adaptive writing to generate a unary function.

Binary function

#include <functional>
#include <list>
#include <algorithm>
#include <iterator>
#include <iostream>
using namespace std;

int main()
{
    multiplies<int> mul;
    list <int> ls = {1,2,3,4,5,6,7};
    for(auto i = ls.begin();i != ls.end();i++)
    {
        *(i) = mul(*(i),2);
    }
    ostream_iterator<int,char> out (cout," ");
    copy(ls.begin(),ls.end(),out);
    return 0;
}

It's obvious that we can use the function adapter (itself a template class)

binder1st -- you can create an object that can associate a value with the first parameter of a binary function, so that the object becomes a unary function

binder2nd -- same as above, but associate a value with the second value of a binary function

Because it is essentially a template class. Pay attention to instantiation when using it

Or these two functions

The same as above, but it is a function without instantiation

bind1st() -- returns a unary function symbol object

bind2nd() -- returns a unary function symbol object

So you can rewrite the code like this

int main()
{
    list <int> ls = {1,2,3,4,5,6,7};
    ostream_iterator<int,char> out (cout," ");
    binder1st< multiplies<int> > my_mul (multiplies<int>(),2);
    transform(ls.begin(), ls.end(),out,my_mul);
    return 0;
}

Or

int main()
{
    list <int> ls = {1,2,3,4,5,6,7};
    ostream_iterator<int,char> out (cout," ");
    transform(ls.begin(), ls.end(),out,bind1st(multiplies<double>(),2));
    return 0;
}

Operation results

The two methods are slightly different, and the method of function will be simpler

Keywords: C++ STL

Added by marconi8 on Wed, 02 Feb 2022 19:14:37 +0200