Software Design

Design de software em C, C++, Java, etc…

C++: Entendendo std::bind*st, std::ptr_fun, std::tr1::bind

Hoje vou falar sobre as funções da STL std::bind1st e std::bind2nd. O que essas funções fazem basicamente é criar um objeto-função ( ou functor ) armazenando um objeto arbitrário que será passado por parâmetro para uma função.

Para exemplificar vamos utilizar o seguinte código:

int add(int value) {
    cout << "add("<<value<<") = "<< value + 1 << endl;
}

int main(int argc, char* argv[]) {
    vector<int> vint;
    vint.push_back(10);
    vint.push_back(15);

    for_each(vint.begin(), vint.end(), add);
}

O que este código faz é: para cada elemento do vint, executa a função add passando como parâmetro para a função o próprio elemento.

O resultado desse código é:

add(10) = 11
add(15) = 16

Ou seja: o método add está sendo chamado para cada elemento ( 10 e 15 ) e imprime o valor da adição do seu parâmetro mais 1.

Agora vamos supor que precisamos melhorar esse código para que o método add receba um segundo parâmetro que é o valor que será adicionado. Fazendo a alteração o código ficaria assim:

int add(int value, int amt) {
    cout << "add("<<value<<") = "<< value + amt << endl;
}

int main(int argc, char* argv[]) {
    vector<int> vint;
    vint.push_back(10);
    vint.push_back(15);

    for_each(vint.begin(), vint.end(), add);
}

Obviamente este código não vai compilar. O compilador vai reclamar de algo como:

usr/include/c++/4.2.1/bits/stl_algo.h: In function ‘_Function std::for_each(_InputIterator, _InputIterator, _Function) [with _InputIterator = __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator > >, _Function = int (*)(int, int)]’:
bind.cpp:15:   instantiated from here
/usr/include/c++/4.2.1/bits/stl_algo.h:159: error: too few arguments to function

Aí é que entram std::bind2nd e std::ptr_fun. A bind2nd cria um objeto-função à partir de um ponteiro para função e um valor arbitrário ( que será utilizado como segundo argumento da função passada por parâmetro ). Já a std::ptr_fun cria um objeto função encapsulando o ponteiro para função passado por parâmetro.

Modificando nosso código para utilizar a nova função add ficaria assim:

#include <iostream>
#include <algorithm>
#include <vector>
#include <functional>

using namespace std;

int add(int value, int amt) {
    cout << "add("<<value<<") = "<< value + amt << endl;
}

int main(int argc, char* argv[]) {
    vector<int> vint;
    vint.push_back(10);
    vint.push_back(15);

    for_each(vint.begin(), vint.end(), 
            bind2nd(ptr_fun(add), 100));
}

Esse código gera a seguinte saída:

add(10) = 110
add(15) = 115

Se o seu compilador C++ tiver suporte à TR1 fica mais fácil. Basta usar a std::tr1::bind em conjunto com os placeholders.

A tr1::bind é basicamente a mesma coisa da boost::bind só que padronizada ( faz parte da linguagem ). A vantagem dela é que podemos utilizar placeholders para definir qual argumento será passado por parâmetro e qual será implícito. Os placeholders são identificadores especiais ( _1, _2 ) e estão em um namespace separado ( std::tr1::placeholders ). Eu recomendo dar um “using namespace std::tr1::placeholders” dentro da função que eles serão usados e não no escopo global.

#include <iostream>
#include <algorithm>
#include <vector>
#include <tr1/functional>

using namespace std;
using namespace tr1::placeholders;

int add(int value, int amt) {
    cout << "add("<<value<<") = "<< value + amt << endl;
}

int main(int argc, char* argv[]) {
    vector<int> vint;
    vint.push_back(10);
    vint.push_back(15);

    for_each(vint.begin(), vint.end(), 
            std::tr1::bind(add, _1, 100));
}

Este post já está extenso demais, em breve vou escrever mais um à respeito da std::tr1::bind e boost::bind!

Um comentário em “C++: Entendendo std::bind*st, std::ptr_fun, std::tr1::bind

  1. Felipe
    agosto 18, 2012

    Parabéns! Muito bom, aguardo o próximo sobre std::bind e boost::bind!

Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

Informação

Publicado às agosto 15, 2012 por em boost, C++ e marcado , , , , , .
%d blogueiros gostam disto: