Pregunta

¿Qué le pasa a la siguiente pequeño programa que pasa un objeto función?

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

Estoy recibiendo el siguiente error en la línea 6:

 no match for call to 
`(const std::unary_function<const std::string&, void>) (const std::string&)'
¿Fue útil?

Solución

Un error común. unary_function y binary_function son sólo dos estructuras que se suman typedefs

argument_type
result_type

y respectivamente

first_argument_type
second_argument_type
result_type

No más. Ellos son para conveniencia de los creadores de tipos de objetos función, por lo que no tiene que hacer los mismos. Pero ellos no se comportan polimórfica. Lo que queremos es función de objeto envoltorio. boost::function viene a la mente:

void foo(boost::function<void(const std::string&)> const& fct) {
  const std::string str = "test";
  fct(str); // no error anymore
}

O que sea una plantilla

template<typename FunctionObject>
void foo(FunctionObject const& fct) {
  const std::string str = "test";
  fct(str); // no error anymore
}

Se puede tomar por su valor y luego devolver la copia de foo si utilizarlo para aplicarlo a alguna secuencia. Lo que permitiría al objeto de función para actualizar algunas variables de estado entre sus miembros. for_each es un ejemplo que lo hace así. En general, de todos modos, yo aceptaría ellos por el valor, ya que son generalmente pequeñas y copiarlos permite una mayor flexibilidad. Por lo que

template<typename FunctionObject>
void foo(FunctionObject fct) {
  const std::string str = "test";
  fct(str); // no error anymore
}

A continuación, será capaz de tomar una copia de FCT y guardarlo en algún lugar, y el operador de fct () puede ser no constante y actualizar algunos miembros (que es parte de todo el punto de operator()). Recuerde que si usted toma un objeto de función por referencia constante, no se puede copiar en general, porque el usuario podría haber pasado una función. Copiarlo y luego tratará de declarar una función localmente en lugar de un puntero de función local. Sin embargo, la aceptación por valor aceptará un puntero de función en su lugar cuando se aprobó una función, que con seguridad se puede copiar.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top