Il passaggio di un oggetto funzione: Errore
-
22-08-2019 - |
Domanda
Cosa c'è di sbagliato con il seguente piccolo programma che passa un oggetto funzione?
#include <iostream>
#include <functional>
void foo(const std::unary_function<const std::string&, void>& fct) {
const std::string str = "test";
fct(str); // error
}
class MyFct : public std::unary_function<const std::string&, void> {
public:
void operator()(const std::string& str) const {
std::cout << str << std::endl;
}
};
int main(int argc, char** argv){
MyFct f;
foo(f);
return 0;
}
sto ottenendo il seguente errore in linea 6:
no match for call to
`(const std::unary_function<const std::string&, void>) (const std::string&)'
Soluzione
Un errore comune. unary_function
e binary_function
sono solo due le strutture che aggiungono typedef
argument_type
result_type
e, rispettivamente,
first_argument_type
second_argument_type
result_type
Non più. Essi sono per comodità di creatori di tipi di oggetti funzione, in modo che non hanno a che fare quelli stessi. Ma non si comportano polimorfica. Ciò che si vuole è la funzione oggetto wrapper. boost::function
viene in mente:
void foo(boost::function<void(const std::string&)> const& fct) {
const std::string str = "test";
fct(str); // no error anymore
}
o ne fanno un modello
template<typename FunctionObject>
void foo(FunctionObject const& fct) {
const std::string str = "test";
fct(str); // no error anymore
}
Si può prendere per valore e quindi restituire la copia da foo
se usarlo per applicarla a qualche sequenza. Che permetterebbe l'oggetto funzione per modificare alcune variabili di stato tra i suoi componenti. for_each
è un esempio che fa così. In generale, comunque, vorrei li accetto per valore perché di solito sono piccoli e copiandoli permette una maggiore flessibilità. Così faccio
template<typename FunctionObject>
void foo(FunctionObject fct) {
const std::string str = "test";
fct(str); // no error anymore
}
Sarà quindi in grado di prendere una copia di FCT e salvarlo da qualche parte, e l'operatore di fct
() può essere non-const e aggiornare alcuni membri (che fa parte del il punto di operator()
). Ricorda che se si prende un oggetto funzione per riferimento const, non si può in genere copiarlo, perché l'utente avrebbe potuto passare una funzione. Copiare poi proverà a dichiarare a livello locale di una funzione invece di un puntatore a funzione locale. Tuttavia, accettando per valore accetta un puntatore a funzione, invece, quando una funzione è stata approvata, che può tranquillamente essere copiato.