Novos recursos do C++ 11 ④ | Classe de modelo std::function e função de biblioteca padrão std::bind

Índice

1. Introdução

2. classe de modelo de função std::function

3. função de biblioteca padrão std::bind

4. Use std::bind e std::function juntos


Resumo do desenvolvimento de funções comuns do VC++ (lista de artigos de coluna, bem-vindo à assinatura, atualizações contínuas...) icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/124272585 série de tutoriais sobre solução de anomalias de software C++ de entrada para proficiência (lista de artigos da coluna), bem-vindo para se inscrever e continuar atualizando...) icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125529931 Ferramentas de análise de software C++ desde a entrada até a coleção de casos de domínio (coluna artigo está sendo atualizado...) icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/131405795 Noções básicas e avançadas de C/C++ (artigo da coluna, atualizado continuamente...) icon-default.png?t=N7T8https://blog.csdn.net /chenlycly/category_11931267.html        Os novos recursos do C++ 11 são muito importantes. Como desenvolvedor C++, é necessário aprendê-los. Eles não apenas serão abordados em exames escritos e entrevistas, mas também serão usados ​​em larga escala em atividades abertas Código fonte. Tomemos como exemplo o projeto WebRTC de código aberto usado por muitos softwares de videoconferência e transmissão ao vivo. O código WebRTC usa extensivamente os novos recursos do C++ 11 e superior. Para entender seu código-fonte, você deve entender esses novos recursos do C++. Portanto, no próximo período, darei a você uma explicação detalhada dos novos recursos do C++ 11 com base na prática de trabalho para referência.

1. Introdução

       C++ 11 introduz uma classe de modelo std::function e uma função de biblioteca padrão std::bind, esses dois recursos tornam o C++ mais flexível. Usar o modelo de classe std::function pode realizar o empacotamento do objeto de chamada. Chame a função de biblioteca padrão std::bind para gerar uma nova função baseada na função original, que é conveniente para chamar. Vamos explicar esses dois novos recursos em detalhes abaixo.

2. classe de modelo de função std::function

       Em C++, as entidades que podem ser chamadas incluem principalmente: funções, ponteiros de função, referências de função, objetos que podem ser convertidos implicitamente em funções especificadas ou objetos que implementam opetator().

       No C++ 11, um novo modelo de classe std::function foi adicionado, que é um wrapper de tipo seguro para entidades que podem ser chamadas existentes em C++. std::function pode armazenar, copiar e chamar instâncias de qualquer destino que pode ser chamado, como uma função, expressão lambda, expressão de ligação ou outro objeto de função, bem como ponteiros para funções de membro e ponteiros para membros de dados. Ao especificar seus parâmetros de modelo, ele pode manipular funções, objetos de função e ponteiros de função de maneira unificada e permitir que eles sejam salvos e atrasados.

       O objeto que pode ser chamado armazenado nesta classe de modelo é chamado de std::function do destino. Se uma instância std::function não contém nenhum destino, ela é considerada vazia. Chamar um objeto std::function vazio fará com que a exceção std::bad_function_call seja lançada.

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

O maior uso do objeto std::function é implementar retornos de chamada de função.Os usuários precisam observar que ele não pode ser usado para verificar igualdade ou desigualdade, mas pode ser comparado com NULL ou nullptr.

3. função std::bind

       std::bind é um mecanismo que pode vincular certos parâmetros de uma entidade que pode ser chamada especificada a variáveis ​​existentes antecipadamente para gerar uma nova entidade que pode ser chamada. Este mecanismo também é muito útil no uso de funções de retorno de chamada. Para ser útil.

Em C++ 98, existem duas funções bind1st e bind2nd, que podem ser usadas para vincular o primeiro e o segundo parâmetros do functor, respectivamente.Eles só podem vincular um parâmetro, e várias restrições fazem com que bind1st e bind2nd A disponibilidade seja bastante reduzida.

       Em C++ 11, std::bind é fornecido. O número de parâmetros que ele vincula não é limitado e os parâmetros específicos a serem vinculados não são limitados. Eles são especificados pelo usuário. Essa ligação é a ligação verdadeira. Certamente. A função de ligação pode ser considerada um adaptador de função geral que recebe um objeto que pode ser chamado e gera um novo objeto que pode ser chamado para "adaptar" a lista de parâmetros do objeto original. A forma geral de chamar bind:

auto newCallable = bind( callable,  arg_lsit);

Entre eles, newCallable é um objeto que pode ser chamado e arg_lsit é uma lista de parâmetros separados por vírgula, correspondendo aos parâmetros passados ​​​​para o objeto que pode ser chamado. Quando chamamos new newCallable, newCallable chama callable e passa os parâmetros em arg_lsit para callable.

       Além disso, os parâmetros em arg_lsit podem conter nomes no formato _n, onde n é um número inteiro. Tais parâmetros são "espaços reservados" e são o enésimo parâmetro passado para newCallable. _n é definido em um namespace chamado placeholders, que está localizado no espaço std, portanto, a instrução using correspondente a _1 é:

using std::placeholders::_1。

         Aqui está um exemplo de uso da função bind para substituir uma expressão lambda. Por exemplo, existe uma lista de vetores que armazena objetos string:

std::vector<string> strList;

Use uma expressão lambda para encontrar elementos em uma lista cujo comprimento de string seja maior ou igual a 6:

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

É relativamente simples de implementar usando funções lambda.

       Se você quiser usar uma função normal para comparar comprimentos de strings, como chamar find_if? Por exemplo, a função para detectar o comprimento de uma string é a seguinte:

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

Como a função de comparação passada para find_if possui apenas um parâmetro, e a função de comparação aqui possui dois parâmetros, ela não pode ser transmitida diretamente. Podemos usar a função bind para construir uma nova função:

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

Aqui está uma string como exemplo para ver o processo de chamada da função bind:

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

Portanto, ao chamar find_if, você pode escrever assim:

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

find_if passa um objeto de classe de string para CheckStrLenBind e, em seguida, CheckStrLenBind passa esse objeto de classe de string como o primeiro parâmetro para a função final CheckStrLen e, ao mesmo tempo, passa dwLen para CheckStrLen.

       Você também pode escrevê-lo diretamente assim:

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

4. Use std::bind e std::function juntos

       Também podemos usar std::bind e std::function juntos, para que todos os objetos que podem ser chamados tenham um método de operação unificado. Veja o exemplo a seguir:

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

Acho que você gosta

Origin blog.csdn.net/chenlycly/article/details/132774379
Recomendado
Clasificación