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&)'
È stato utile?

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top