C++11 new features ④ | Template class std::function and standard library function std::bind

Table of contents

1 Introduction

2. std::function function template class

3. std::bind standard library function

4. Use std::bind and std::function together


Summary of the development of common functions of VC++ (list of column articles, welcome to subscribe, continuous updates...) icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/124272585 C++ software anomaly troubleshooting series of tutorials from entry to proficiency (list of column articles) , welcome to subscribe and continue to update...) icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125529931 C++ software analysis tools from entry to mastery case collection (column article is being updated...) icon-default.png?t=N7T8https:/ /blog.csdn.net/chenlycly/article/details/131405795 C/C++ basics and advanced (column article, continuously updated...) icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_11931267.html        C++ 11 new features are very important. As a C++ developer, it is necessary to learn them. Not only will they be covered in written exams and interviews, but they will also be used on a large scale in open source code. Take the open source WebRTC project used by many video conferencing and live broadcast software as an example. The WebRTC code extensively uses the new features of C++11 and above. To understand its source code, you must understand these new features of C++. Therefore, in the next period of time, I will give you a detailed explanation of the new features of C++11 based on work practice for reference.

1 Introduction

       C++11 introduces a template class std::function and a standard library function std::bind. These two features make C++ more flexible. The calling object can be wrapped using the std::function class template. Call the standard library function std::bind to generate a new function based on the original function for easy calling. Let’s explain these two new features in detail below.

2. std::function function template class

       In C++, callable entities mainly include: functions, function pointers, function references, objects that can be implicitly converted to functions specified, or objects that implement opetator().

       In C++11, a new std::function class template is added, which is a type-safe wrapper for existing callable entities in C++. std::function can store, copy, and call instances of any callable target, such as a function, lambda expression, bind expression, or other function object, as well as pointers to member functions and pointers to data members. By specifying its template parameters, it can handle functions, function objects, and function pointers in a unified way, and allow them to be saved and delayed.

       The callable object stored in this template class is called the target's std::function. If an std::function instance contains no target, it is said to be empty. Calling an empty std::function object will cause the exception std::bad_function_call to be thrown.

#include <iostream>
#include <functional>   //std::cout
using namespace std;

void func(void)
{//普通全局函数
    cout << __func__ << endl;
}

class Foo
{
public:
    static int foo_func(int a)
    {//类中静态函数
        cout << __func__ << "(" << a << ") ->: ";
        return a;
    }
};

class Bar
{
public:
    int operator()(int a)
    {//仿函数
        cout << __func__ << "(" << a << ") ->: ";
        return a;
    }
};

int main()
{
    //绑定一个普通函数
    function< void(void) > f1 = func;
    f1();

    //绑定类中的静态函数
    function< int(int) > f2 = Foo::foo_func;
    cout << f2(111) << endl;

    //绑定一个仿函数
    Bar obj;
    f2 = obj;
    cout << f2(222) << endl;

    /*
     运行结果:
        func
        foo_func(111) ->: 111
        operator()(222) ->: 222
    */

    return 0;
}

The biggest use of the std::function object is to implement function callbacks. Users need to note that it cannot be used to check equality or inequality, but it can be compared with NULL or nullptr.

3. std::bind function

       std::bind is a mechanism that can bind certain parameters of a specified callable entity to existing variables in advance to generate a new callable entity. This mechanism is also very useful in the use of callback functions. To be useful.

In C++98, there are two functions bind1st and bind2nd, which can be used to bind the first and second parameters of functor respectively. They can only bind one parameter, and various restrictions make bind1st and bind2nd The availability is greatly reduced.

       In C++11, std::bind is provided. The number of parameters it binds is not limited, and the specific parameters to be bound are not limited. They are specified by the user. This bind is the true binding. Certainly. The bind function can be thought of as a general function adapter that receives a callable object and generates a new callable object to "adapt" the parameter list of the original object. The general form of calling bind:

auto newCallable = bind( callable,  arg_lsit);

Among them, newCallable is a callable object, and arg_lsit is a comma-separated parameter list, corresponding to the parameters passed to the callable callable object. When we call new newCallable, newCallable calls callable and passes the parameters in arg_lsit to callable.

       In addition, the parameters in arg_lsit may contain names of the form _n, where n is an integer. Such parameters are "placeholders" and are the nth parameter passed to newCallable. _n is defined in a namespace called placeholders, which is located in the std space, so the using statement corresponding to _1 is:

using std::placeholders::_1。

         Here is an example of using the bind function to replace a lambda expression. For example, there is a vector list that stores string objects:

std::vector<string> strList;

Use a lambda expression to find elements in a list whose string length is greater than or equal to 6:

DWORD dwLen = 6;
find_if( strList.begin(), strList.end(), [dwLen](const string & str )
{ str.size() >= dwLen;}); // 使用lambda表达式

It is relatively simple to implement using lambda functions.

       If you want to use a normal function to compare string lengths, how to call find_if? For example, the function to detect the length of a string is as follows:

bool CheckStrLen( const string& str,  DWORD dwLen )
{
    return str.size() >= dwLen;
}

Because the comparison function passed to find_if has only one parameter, and the comparison function here has two parameters, it cannot be passed in directly. We can use the bind function to construct a new function:

DWORD dwLen = 6;
auto CheckStrLenBind = bind( CheckStrLen, _1, dwLen );  // 调用CheckStrLenBind,就会调用CheckStrLen,然后给CheckStrLen传递两个参数

Here is a string as an example to see the bind function calling process:

DWORD dwLen = 6;
auto CheckStrLenBind = bind( CheckStrLen, _1, dwLen ); 
string str = “hello”;
bool bRet = CheckStrLenBind( str ); // 此处相当于调用CheckStrLen(str, dwLen)

Therefore, when calling find_if, you can write like this:

DWORD dwLen = 6;
auto CheckStrLenBind = bind( CheckStrLen, _1, dwLen ); 
find_if(  strList.begin(), strList.end(), CheckStrLenBind);

find_if passes a string class object to CheckStrLenBind, and then CheckStrLenBind passes this string class object as the first parameter to the final function CheckStrLen, and at the same time passes dwLen to CheckStrLen.

       You can also write it directly like this:

find_if(  strList.begin(), strList.end(), bind( CheckStrLen, _1, dwLen ));

4. Use std::bind and std::function together

       We can also use std::bind and std::function together, so that all callable objects have a unified operation method. Look at the following example:

#include <iostream>
#include <functional>   //std::cout
using namespace std;
using namespace std::placeholders;    // adds visibility of _1, _2, _3,...

class Test
{
public:
    int i = 0;

    void func(int x, int y)
    {
        cout << x << " " << y << endl;
    }
};

int main()
{
    Test obj; //创建对象

    function<void(int, int)> f1 = bind(&Test::func, &obj, _1, _2);
    f1(1, 2);   //输出:1 2

    function< int &()> f2 = bind(&Test::i, &obj);
    f2() = 123;
    cout << obj.i << endl;//结果为 123

    return 0;
}

Guess you like

Origin blog.csdn.net/chenlycly/article/details/132774379