Detailed explanation of C++11 bind function forward usage

16636829:

Table of contents

std::bind

std::function

std::forward


std::bind

std::bind Is a function template, defined in  <functional> the header file. Its function is to bind a callable object (such as a function, function pointer, member function, member function pointer, etc.) and several parameters to a new function object to form a new callable object.

std::bind The function signature is as follows:

template< class F, class... Args >
constexpr /*unspecified*/ bind( F&& f, Args&&... args );

Among them, F represents the callable object type to be bound, and Args represents the parameter type to be bound. std::bind Returns a new function object that can be called. When called, the bound callable object will be executed and the bound parameters will be passed to it.

Here is an example that demonstrates how to use  std::bind functions to bind a normal function to a new function object:

#include <iostream>
#include <functional>

int add(int a, int b) {
    return a + b;
}

int main() {
    auto add_five = std::bind(add, 5, std::placeholders::_1);
    std::cout << add_five(3) << std::endl; // 输出 8
    return 0;
}

In this example, we use  std::bind function to  add bind the function to a new function object  add_five and bind 5 to  add the first parameter of the function and  _1 the placeholder to  add the second parameter of the function. Then, when calling  add_five(3) , we pass 3 as  _1 the placeholder value, and add_five the function object calls  add(5, 3) the function and returns the result 8.

When using  std::bind functions, you can use placeholders to specify which parameters need to be passed when calling the function object and which parameters need to be passed when binding. Commonly used placeholders are:

  • _1: Indicates the first parameter when calling the function object.
  • _2: Indicates the second parameter when calling the function object.
  • _3: Indicates the third parameter when calling the function object.
  • ...

For example, if we want to pass the first and third parameters when calling the function object, and the second parameter when binding, we can use placeholders like this:

auto foo = std::bind(func, std::placeholders::_1, arg2, std::placeholders::_3);

When binding parameters, you can also use  std::ref a function to wrap a variable into a reference so that it can be passed by reference when calling the function object. For example:

int x = 42;
auto foo = std::bind(func, std::ref(x), std::placeholders::_1);

Here, we  x wrap the variable into a reference and bind it to  func the function along with the placeholder. When calling  foo a function object, the first argument will be  x a reference to .

In addition to  std::bind functions, C++11 also provides a new language feature - Lambda expressions, which can be used to replace  std::bind functions. Lambda expressions can more flexibly implement function object binding and parameter passing. For example:

auto add_five = [](int x) { return add(5, x); };
std::cout << add_five(3) << std::endl; // 输出 8

In this example, we use a Lambda expression to  add(5, x) bind the function to a new function object  add_five and pass 3 as an argument to it. add_five The function object calls  add(5, 3) the function and returns the result 8.

std::function

Type was introduced in C++11  std::function , which is a polymorphic function wrapper class that can be used to store and call any callable object, including function pointers, function objects, Lambda expressions, etc.

std::function The function signature is as follows:

template <typename Signature>
class function;

Which  Signature represents the signature of the callable object, including the return value type and parameter list. For example, a return  int type,  int the signature of a function that accepts two type parameters is  int(int, int).

std::functionoperator() A type can bind a callable object through a constructor or assignment operator, and can use operators to execute it  when the object needs to be called  .

Here is an example that demonstrates how to use  std::function types to store and call a Lambda expression:

#include <iostream>
#include <functional>

int main() {
    std::function<int(int, int)> add = [](int x, int y) { return x + y; };
    std::cout << add(3, 4) << std::endl; // 输出 7
    return 0;
}

In this example, we define an  std::function<int(int, int)> object of type  addand use a Lambda expression to bind it to a function that returns the sum of two arguments. Then, when calling  add(3, 4) , we pass 3 and 4 as parameters and execute  [](int x, int y) { return x + y; } the Lambda expression, returning 7 as a result.

std::function The type also supports comparison between empty function objects and function objects. You can use  operator bool() operators to determine whether the object is empty, and use  operator== the AND  operator!= operator to compare whether two function objects are equal.

Here is an example that demonstrates how to use  std::function types for comparison of function objects:

#include <iostream>
#include <functional>

int main() {
    std::function<void()> func1 = []() { std::cout << "Hello, world!" << std::endl; };
    std::function<void()> func2;
    std::cout << std::boolalpha << (func1 == func2) << std::endl; // 输出 false
    func2 = func1;
    std::cout << std::boolalpha << (func1 == func2) << std::endl; // 输出 true
    return 0;
}

In this example, we define two  std::function<void()> types of objects  func1 and  bind func2them  func1 to a Lambda expression. Then, when comparing  the sums func1 for  func2 equality, we use  operator== operators and output the comparison results. Since  func2 it has not been bound to any callable object at this time, the sum  func1 is  func2 not equal and false is output. Next, we  func2 bind to  func1 the same callable object as , compare them again for equality, and output the comparison result. At this time, the sum is equal func1 and  func2 true is output.

std::forward

std::forward It is a function template in the C++11 standard library, used to forward parameters perfectly. Its main function is to forward the incoming parameters according to their value categories (lvalue or rvalue) in the function template to keep their value categories unchanged, thereby avoiding unnecessary copy and move operations.

std::forward The function signature is as follows:

template <typename T>
constexpr T&& forward(typename std::remove_reference<T>::type& arg) noexcept;
template <typename T>
constexpr T&& forward(typename std::remove_reference<T>::type&& arg) noexcept;

Among them, the first template parameter  T indicates the type of parameter to be forwarded. If the parameter is an lvalue reference type, then  T it is the base type of this reference type. If the parameter is an rvalue reference type, then  T the base type of the rvalue reference type is added  &&.

std::forward The function is to forward the incoming parameters  arg to another function (usually a template function) and maintain its original value category. During the forwarding process, if the parameter is an lvalue reference type, the forwarded type is also an lvalue reference type. If the parameter is an rvalue reference type, the forwarded type is also an rvalue reference type.

Here is an example that demonstrates how to use  std::forward for perfect forwarding:

cpp

Copy

#include <utility>
#include <iostream>

void foo(int& x) {
    std::cout << "lvalue" << std::endl;
    ++x;
}

void foo(int&& x) {
    std::cout << "rvalue" << std::endl;
    ++x;
}

template <typename T>
void bar(T&& x) {
    std::forward<T>(x);
    foo(std::forward<T>(x));
}

int main() {
    int i = 42;
    bar(i);          // 输出 "lvalue"
    std::cout << i;  // 输出 43
    bar(42);         // 输出 "rvalue"
    return 0;
}

In this example, we define two functions  foothat accept parameters of an lvalue reference type and an rvalue reference type respectively. Then, we define a template function  barthat accepts a parameter  xof type  T&&. In  bar the function, we use  std::forward perfect  x forward to  foo the function and keep its value category unchanged. When  bar the function is called, if the parameter passed in is an lvalue, the  bar function will call  foo(int&) the function and output "lvalue". In  foo(int&) the function, we increment the parameter by one and store the result back to the original parameter. So when we output  i the value, its value becomes 43. If the argument passed in is an rvalue,  bar the function will call  foo(int&&) the function and output "rvalue". In  foo(int&&) the function, we increment the argument by one, but since it is an rvalue, we cannot modify its value. Therefore, in this example, we only demonstrate  std::forward the use without actually modifying the value of the parameter.

Guess you like

Origin blog.csdn.net/weixin_40582034/article/details/132040437