Ancora su boost::bind

Rileggendo Beyond the C++ Standard Library: An Introduction to Boost di Björn Karlsson.

Parte sull'uso di bind, nel capitolo nove, all'interno della terza parte, dedicata ai functor e alla programmazione di più alto ordine.

L'uso di boost::bind é estremamente flessibile. Nell'esempio che segue si vede come il confronto con std::mem_fun_ref la veda vincente.


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

#include "boost/bind.hpp"

using namespace std;

class status {
string name_;
bool ok_;
public:
status(const string& name) : name_(name), ok_(true) {}

void breakIt() {
ok_=false;
}

bool isBroken() const {
return ok_;
}

void report() const {
cout << name_ << " is " << (ok_ ? "working" : "broken") << endl;
}
};

void bind01() {
vector<status> statuses;
statuses.push_back(status("status 1"));
statuses.push_back(status("status 2"));
statuses.push_back(status("status 3"));
statuses.push_back(status("status 4"));

statuses[1].breakIt();
statuses[2].breakIt();

cout << "Using a classic for loop" << endl;
for (vector<status>::iterator it = statuses.begin(); it != statuses.end(); ++it) {
it->report();
}

cout << "Using for_each and mem_fun_ref" << endl;
for_each(statuses.begin(), statuses.end(), mem_fun_ref(&status::report));

cout << "Using for_each and boost::bind" << endl;
for_each(statuses.begin(), statuses.end(), boost::bind(&status::report, _1));
}

Il bello di boost::bind é che funziona quando il parametro passato, identificato con il segnaposto _1, può essere un valore, un puntatore, o anche uno smart pointer. Usando le funzionalità offerte dalla libreria standard (in attesa della riscrittura 0x) occorre usare l'adattatore mem_fun_ref, mem_fun, o disperarsi per l'assenza di disponibilità per smart pointer.

Nell'esempio seguente vediamo come boost::bind lavori indifferentemente con funzioni libere o membri di classi. Bisogna solo fare attenzione ai parametri passati via segnaposto. Nel caso di funzioni membro non statiche, che richiedano quindi un "this" su cui operare, il primo segnaposto deve essere dedicato a un oggetto della classe a cui fare riferimento.

#include <iostream>
#include <string>
#include "boost/bind.hpp"

using namespace std;

class AClass {
public:
void printString(const string& s) const {
cout << "Member function: " << s << endl;
}

static void staticPrintString(const string& s) {
cout << "Static member function: " << s << endl;
}
};

void printString(const string& s) {
cout << "Free function: " << s << endl;
}

void bind02() {
boost::bind(&printString, _1)("Hello!"); // 1

boost::bind(&AClass::staticPrintString, _1)("Hello!"); // 2

AClass c;
boost::bind(&AClass::printString, _1, _2)(c, "Hello!"); // 3

boost::bind(&AClass::printString, AClass(), _1)("Hello!"); // 4

boost::bind(&AClass::printString, AClass(), "Hello!")(); // 5
}

Nel primo esempio boost::bind invoca una funzione libera, passandole via il primo segnaposto, _1, una stringa. Nel secondo ad essere chiamata é una funzione statica, nel terzo una normale funzione membro, che ha bisogno di un "this" per operare, e che viene estratto dall'istanza di AClass che viene passata come _1.

Nel quarto esempio vediamo che é posibile passare esplicitamente a bind un'istanza della classe costruita al volo. In questo caso il primo segnaposto viene dedicato al parametro della funzione. Il quinto esempio permette di fare a meno dell'uso di ogni segnaposto, dato che bind prende in input il puntatore alla funzione, il puntatore a un oggetto della classe creato al volo e il parametro passato alla funzione.

Nessun commento:

Posta un commento