Explicación detallada del uso directo de la función de vinculación de C++11

Tabla de contenido

std::enlazar

std::función

std::adelante


std::bind

std::bind Es una plantilla de función, definida en  <functional> el archivo de encabezado. Su función es vincular un objeto invocable (como una función, puntero de función, función miembro, puntero de función miembro, etc.) y varios parámetros a un nuevo objeto de función para formar un nuevo objeto invocable.

std::bind La firma de la función es la siguiente:

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

Entre ellos, F representa el tipo de objeto invocable que se vinculará y Args representa el tipo de parámetro que se vinculará. std::bind Devuelve un nuevo objeto de función que se puede llamar. Cuando se llama, el objeto invocable vinculado se ejecutará y se le pasarán los parámetros vinculados.

A continuación se muestra un ejemplo que demuestra cómo utilizar  std::bind funciones para vincular una función normal a un nuevo objeto de función:

#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;
}

En este ejemplo, usamos  std::bind función para  add vincular la función a un nuevo objeto de función  add_five y vinculamos 5 al  add primer parámetro de la función y  _1 el marcador de posición al  add segundo parámetro de la función. Luego, al llamar  add_five(3) , pasamos 3 como  _1 valor de marcador de posición, y add_five el objeto de función llama  add(5, 3) a la función y devuelve el resultado 8.

Al usar  std::bind funciones, puede usar marcadores de posición para especificar qué parámetros deben pasarse al llamar al objeto de función y qué parámetros deben pasarse al vincularse. Los marcadores de posición comúnmente utilizados son:

  • _1: Indica el primer parámetro al llamar al objeto de función.
  • _2: Indica el segundo parámetro al llamar al objeto de función.
  • _3: Indica el tercer parámetro al llamar al objeto de función.
  • ...

Por ejemplo, si queremos pasar el primer y tercer parámetro al llamar al objeto de función y el segundo parámetro al vincularlo, podemos usar marcadores de posición como este:

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

Al vincular parámetros, también puede usar  std::ref una función para envolver una variable en una referencia para que pueda pasarse por referencia al llamar al objeto de función. Por ejemplo:

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

Aquí,  x envolvemos la variable en una referencia y la vinculamos a  func la función junto con el marcador de posición. Al llamar  foo a un objeto de función, el primer argumento será  x una referencia a .

Además de  std::bind las funciones, C++ 11 también proporciona una nueva característica de lenguaje: las expresiones Lambda, que se pueden usar para reemplazar  std::bind funciones. Las expresiones Lambda pueden implementar de manera más flexible la vinculación de objetos de función y el paso de parámetros. Por ejemplo:

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

En este ejemplo, usamos una expresión Lambda para  add(5, x) vincular la función a un nuevo objeto de función  add_five y le pasamos 3 como argumento. add_five El objeto de función llama  add(5, 3) a la función y devuelve el resultado 8.

std::function

Type se introdujo en C++ 11  std::function , que es una clase contenedora de funciones polimórfica que se puede usar para almacenar y llamar a cualquier objeto invocable, incluidos punteros de función, objetos de función, expresiones Lambda, etc.

std::function La firma de la función es la siguiente:

template <typename Signature>
class function;

Que  Signature representa la firma del objeto invocable, incluido el tipo de valor de retorno y la lista de parámetros. Por ejemplo, un  int tipo de retorno,  int la firma de una función que acepta dos parámetros de tipo es  int(int, int).

std::functionoperator() Un tipo puede vincular un objeto invocable a través de un constructor u operador de asignación, y puede usar operadores para ejecutarlo  cuando sea necesario llamar al objeto  .

A continuación se muestra un ejemplo que demuestra cómo utilizar  std::function tipos para almacenar y llamar a una expresión Lambda:

#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;
}

En este ejemplo, definimos un  std::function<int(int, int)> objeto de tipo  addy usamos una expresión Lambda para vincularlo a una función que devuelve la suma de dos argumentos. Luego, al llamar  add(3, 4) , pasamos 3 y 4 como parámetros y ejecutamos  [](int x, int y) { return x + y; } la expresión Lambda, devolviendo 7 como resultado.

std::function El tipo también admite la comparación entre objetos de función vacíos y objetos de función. Puede usar  operator bool() operadores para determinar si el objeto está vacío y usar  operator== el operador AND  operator!= para comparar si dos objetos de función son iguales.

A continuación se muestra un ejemplo que demuestra cómo utilizar  std::function tipos para comparar objetos de función:

#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;
}

En este ejemplo, definimos dos  std::function<void()> tipos de objetos  func1 y  func2los  vinculamos func1 a una expresión Lambda. Luego, al comparar  las sumas func1 para  func2 determinar la igualdad, usamos  operator== operadores y generamos los resultados de la comparación. Dado que  func2 no se ha vinculado a ningún objeto invocable en este momento, la suma  no func1 es  func2 igual y se genera false. A continuación, nos  func2 vinculamos al  func1 mismo objeto invocable que , los comparamos nuevamente para determinar la igualdad y generamos el resultado de la comparación. En este momento, func1 la  func2 suma es igual y se genera verdadero.

std::forward

std::forward Es una plantilla de funciones en la biblioteca estándar C++ 11, que se utiliza para reenviar parámetros perfectamente. Su función principal es reenviar los parámetros entrantes de acuerdo con sus categorías de valor (lvalue o rvalue) en la plantilla de función para mantener sus categorías de valor sin cambios, evitando así operaciones innecesarias de copiar y mover.

std::forward La firma de la función es la siguiente:

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;

Entre ellos, el primer parámetro de plantilla  T indica el tipo de parámetro que se reenviará. Si el parámetro es un tipo de referencia lvalue, entonces  T es el tipo base de este tipo de referencia. Si el parámetro es un tipo de referencia rvalue, entonces  T se agrega el tipo base del tipo de referencia rvalue  &&.

std::forward La función es reenviar los parámetros entrantes  arg a otra función (generalmente una función de plantilla) y mantener su categoría de valor original. Durante el proceso de reenvío, si el parámetro es un tipo de referencia lvalue, el tipo reenviado también es un tipo de referencia lvalue. Si el parámetro es un tipo de referencia rvalue, el tipo reenviado también es un tipo de referencia rvalue.

A continuación se muestra un ejemplo que demuestra cómo utilizarlo  std::forward para un reenvío perfecto:

cpp

Copiar

#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;
}

En este ejemplo, definimos dos funciones  fooque aceptan parámetros de un tipo de referencia lvalue y un tipo de referencia rvalue respectivamente. Luego, definimos una función de plantilla  barque acepta un parámetro  xde tipo  T&&. En  bar la función, utilizamos   el reenvío  std::forward perfecto  a  la función y mantenemos su categoría de valor sin cambios. Cuando   se llama a la función, si el parámetro pasado es un valor l, la   función llamará   a la función y generará "valor l". En   la función, incrementamos el parámetro en uno y almacenamos el resultado en el parámetro original. Entonces, cuando generamos   el valor, su valor se convierte en 43. Si el argumento pasado es un rvalue,   la función llamará   a la función y generará "rvalue". En   la función incrementamos el argumento en uno, pero como es un valor r, no podemos modificar su valor. Por lo tanto, en este ejemplo, solo demostramos   el uso sin modificar realmente el valor del parámetro.xfoobarbarfoo(int&)foo(int&)ibarfoo(int&&)foo(int&&)std::forward

Supongo que te gusta

Origin blog.csdn.net/weixin_40582034/article/details/132040437
Recomendado
Clasificación