Pregunta

Me preguntaba si alguien me puede ayudar con funtores. Yo realmente no entiendo lo funtores son y cómo funcionan He intentado googling pero todavía no lo entiendo. ¿cómo functors de trabajo y cómo funcionan con plantillas

¿Fue útil?

Solución

Un funtor es básicamente un "objeto de la función". Es una función única que ha envuelto en una clase o estructura, y que puede pasar a otras funciones.

Trabajan mediante la creación de su propia clase o estructura que sobrecarga el operador de llamada de función (llamado operador ()). Por lo general, se crea una instancia de ella simplemente construirlo en el lugar como un argumento a su función que toma un funtor.

Supongamos que tenemos el siguiente:

std::vector<int> counts;

Ahora, desea incrementar todos los cargos que están contenidas en ese vector. Se podía recorrer manualmente para incrementar, o se puede utilizar un funtor. Un funtor adecuado, en este caso, sería el siguiente:

struct IncrementFunctor
{
    int operator() (int i)
    {
        return i + 1;
    }
}

IncrementFunctor es ahora un funtor que tiene cualquier número entero y los incrementos de TI. Para aplicarlo a los cargos, se puede utilizar el std :: función de transformación, que toma un funtor como argumento.

std::transform(
    counts.begin(),       // the start of the input range
    counts.end(),         // the end of the input range
    counts.begin(),       // the place where transform should place new values. 
                          // in this case, we put it right back into the original list.
    IncrementFunctor());  // an instance of your functor

El IncrementFunctor sintaxis () crea una instancia de ese funtor que luego se pasa directamente a std :: transformar. Se podría, por supuesto, crear una instancia como una variable local y lo pasa, pero esto es mucho más conveniente.

Ahora, en las plantillas. El tipo de funtor en std :: transformar es un argumento de plantilla. Esto se debe a std :: transformar no sabe (o cuidado!) De las cuales introduce tu funtor es. Todo lo que le importa es que tiene un operador de montaje () define, para los que puede hacer algo como

newValue = functor(oldValue);

El compilador es muy inteligente acerca de las plantillas, ya menudo puede averiguar por sí mismo lo que los argumentos de plantilla son. En este caso, el compilador realiza automáticamente que estás pasando en un parámetro de tipo IncrementFunctor, que se define como un tipo de plantilla en std :: transformar. Se hace lo mismo con la lista, también, por lo que el compilador reconoce automáticamente que la llamada real se vería así:

std::transform<std::vector<int>::iterator, // type of the input iterator
               std::vector<int>::iterator, // type of the output iterator
               IncrementFunctor>(          // type of your functor
    counts.begin(),       // the start of the input range
    counts.end(),         // the end of the input range
    counts.begin(),       // the place where transform should place new values. 
                          // in this case, we put it right back into the original list.
    IncrementFunctor());  // an instance of your functor

Esto le ahorra un poco de escribir. ;)

Otros consejos

Un funtor es algo que se puede invocar / llamada con el operador de llamada de función , sintácticamente añadiendo (), opcionalmente con una lista de argumentos dentro de los paréntesis.

Eso es todo lo que necesita un plantilla. La cosa en la que este se invoca, en lo que se refiere a una plantilla, es todo aquello que permita esta sintaxis - o en otras palabras, ya sea una función libre o una instancia de una clase que anula operator()(). (Una función de "libre" es sólo uno que no es miembro, es decir, se trata de una función en el ámbito global o una función en el ámbito de un espacio de nombres incluida anteriormente.)

Fuera de metaprogramming plantilla, que por lo general no dicen que una función libre es un functor, y se reserva ese nombre para una instancia de una clase que anula operator()():

struct Foo {
 public:
   void operator()( int i ) { // do something }
   void operator()( int i, char x ) { // do something else }
}

En las plantillas de C ++ se compilan, por lo que siempre que el sintaxis tiene sentido , el compilador utilizará felizmente una función o un funtor:

template<typename T> class Bar {
  private int j ;
  public:
    Bar( int i ) : j(i) {}
    void doIt(T t) {
     t( j ) ;
  }
}

Foo f;
extern void resize( int i ) ; // in some header

Bar<Foo> bf( 5 ) ;
// a Bar that is templated on Foo
Bar< void (&)(int)   > br( 5 ) ; 
// a Bar that is templated on a function taking int and returning void

br.doit( &resize ) ; // call resize with br.j
bf.doit( f ) ; // call Foo::operator()(int) on Foo f with bf.j
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top