Functors and callable object types

1. The concept and advantages of functors

A functor is a class that overloads the call operator and imitates a function. Its advantages are:

  • flexible. Has storage status;
  • Efficient. Compiler inline optimization;

A functor is a function object, which can be used as a parameter of a generic algorithm. Let's see how it works from an example:

// 这是一个仿函数
struct add_x {
    
    
  add_x(int val) : x(val) {
    
    }  // 构造函数,构造仿函数加数
  int operator()(int y) const {
    
     return x + y; }

private:
  int x;
};
// 你可以这么使用它:
add_x add42(42); // 创建一个仿函数类实例,
int i = add42(8); // 然后调用它,告诉仿函数谁加42 这样一来,就完成了一次仿函数的调用

The constructor of the functor gives the function state int x. From operator(int y)the result, the class name means "what do you want to pass in the parameter". Obviously, this simple example is to add 42 to the passed parameter. In addition, functors can also be used as algorithm parameters:

std::vector<int> in{
    
    1,2,3,4,5,6,7,8,9,10}; // 假设这个容器包含一系列的值
std::vector<int> out(in.size());
// 传递一个仿函数给std::transform,这个算法对输入序列上所有的元素都调用仿函数
// 然后结果存储在输出序列
std::transform(in.begin(), in.end(), out.begin(), add_x(1)); 

std::transformThe function of the algorithm is: let each element of the specified range container be passed into the function object as a parameter, and the execution result of the function object on the parameter will be output to the specified container. The last point is that functors can improve efficiency (compared to ordinary function objects), and the compiler will optimize them inline.

2. Predefined functors

The standard library #include <functional>defines a set of classes representing arithmetic, relational, and logical operators. Each class defines a call operator for performing named operations. The specific situation can be viewed: https://en.cppreference.com/w/cpp/header/functional . Operators such as + - >relations == !=, logic, && ||etc., if we need to sort a container, by default, use the standard std::sort, standard algorithm library container type to define its own sorting logic, such as small to large (ascending order):

std::vector<double> dvec{
    
    11,3,4,5,13,2};
sort(dvec.begin(),dvec.end())

The result is: 2 3 4 5 11 13, so how to descend? The generic algorithm also accepts a function object to change its sorting behavior:

bool cmp(double a, double b)
{
    
    
	return a > b;
}
sort(dvec.begin(), dvec.end(),cmp);

cmpIs a function object, used to define how to sort. cmpSequentially accepts two parameters, and to give athen bordered is correct. If it is correct, return true, otherwise return false. The standard library defines these frequently used judgment logics in advance, such as the above cmpfunction names can be std::greater()substituted. Next time the algorithm needs to pass in a predicate, you might as well see if the functor is implemented.

3. The function standard library unifies the callable types

C++ has the following callable object types

  • function
  • Function pointer
  • lambda expression
  • Object created by bind
  • Functor

Suppose we have the following callable types. Although they implement different functions, they belong to the same type from the point of view of function pointers int(int int).

int add(int i,int j){
    
    return i+j;}
auto mod=[](int i,int j){
    
    return i+j;}
struct divide{
    
    
	int operator()(int denominator,int divisor){
    
    
		return denominator/divisor;
	}
}

In order to facilitate the call, we may need to put it in a function container, the professional point is called the function table (function table), the easiest is to use map.

map<string,int(*)(int,int)> binops;
binops.insert("+",add);//ok
binops.insert("%",mod);//not ok

The above-mentioned mapvalue type is given at the time of definition int(*)(int,int). It modis an expression rather than a function pointer, so it cannot be added to the function table. At this time, there are functiontemplates and function templates #include <functional>that dominate the world . For specific operations, please refer to https://en.cppreference.com/w/cpp/utility/functional/function . Callable objects can be placed through this class package. One piece:

map<string,function<int(int,int)>> binops={
    
    
	{
    
    "+",add},
	{
    
    "-",std::minus<int>},
	{
    
    "*",[](int i,int j){
    
    return i*j;},
	{
    
    "%",mod}
};
binops["+"](10,5);//10-5
binops["-"](4,5);//4-5

lambda expression

An article I wrote before

[1] https://stackoverflow.com/questions/52327464/callback-vs-lambda-in-java
[2] https://stackoverflow.com/questions/356950/what-are-c-functors-and-their-uses

Guess you like

Origin blog.csdn.net/weixin_39258979/article/details/113276589