¿Cómo puede ser útil sobrecargar el operador de "llamada a la función"?


Recientemente descubrí que en C++ se puede sobrecargar el operador "llamada a función", de una manera extraña en la que hay que escribir dos pares de paréntesis para hacerlo:

class A { 
  int n;
public: 
  void operator ()() const; 
};

Y luego úsalo de esta manera:

A a;
a();

¿Cuándo es útil esto?

Author: Fred Nurk, 2010-02-28

7 answers

Esto se puede usar para crear "functors" , objetos que actúan como funciones:

class Multiplier {
public:
    Multiplier(int m): multiplier(m) {}
    int operator()(int x) { return multiplier * x; }
private:
    int multiplier;
};

Multiplier m(5);
cout << m(4) << endl;

Las impresiones anteriores 20. El artículo de Wikipedia enlazado arriba da ejemplos más sustanciales.

 27
Author: Greg Hewgill,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-06 07:57:27

Hay poco más que una ganancia sintáctica al usar operator() hasta que comiences a usar plantillas. Pero cuando se utilizan plantillas se puede tratar las funciones reales y los funtores (clases que actúan como funciones) de la misma manera.

class scaled_sine
{
    explicit scaled_sine( float _m ) : m(_m) {}
    float operator()(float x) const { return sin(m*x); }
    float m;
};

template<typename T>
float evaluate_at( float x, const T& fn )
{
   return fn(x);
}

evaluate_at( 1.0, cos );
evaluate_at( 1.0, scaled_sine(3.0) );
 16
Author: Michael Anderson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-06 02:16:05

A un algoritmo implementado usando una plantilla no le importa si la cosa que se llama es una función o un funtor, le importa la sintaxis. Ya sea estándar (por ejemplo, for_each ()) o el suyo propio. Y los funtores pueden tener estado, y hacer todo tipo de cosas cuando se les llama. Las funciones solo pueden tener estado con una variable local estática o variables globales.

 5
Author: paul,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-28 03:06:07

Si está creando una clase que encapsula un puntero de función, esto podría hacer que el uso sea más obvio.

 1
Author: Reed Copsey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-28 02:56:52

El compilador también puede insertar el funtor y la llamada a la función. Sin embargo, no puede insertar un puntero de función. De esta manera, el uso del operador de llamada de función puede mejorar significativamente el rendimiento cuando se utiliza, por ejemplo, con los algoritmos libary estándar de C++.

 1
Author: fintux,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-27 10:32:00

Por ejemplo para implementar generadores:

// generator
struct Generator {
    int c = 0;

    virtual int operator()() {
        return c++;
    }
};

int sum(int n) {
    Generator g;

    int res = 0;
    for( int i = 0; i < n; i++ ) {
        res += g();
    }

    return res;
}
 0
Author: Quonux,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-05 23:26:29

Veo potencial para todavía un uso exótico:

Supongamos que tiene un objeto de tipo desconocido y tiene que declarar otra variable del mismo tipo, así:

 auto c=decltype(a*b)(123);

Cuando este patrón se usa ampliamente, decltype se vuelve muy molesto. Este caso puede ocurrir cuando se utiliza algún sistema de tipo inteligente que inventa automáticamente el tipo de resultado de funciones y operadores basados en tipos de argumentos.

Ahora, si cada especialización de cada tipo de ese tipo de sistema equipado con definición mágica de operator() así:

template<????> class Num<???>{
    //specific implementation here
    constexpr auto operator()(auto...p){return Num(p...);}
}

decltype() no más necesario, puede escribir simplemente:

auto c=(a*b)(123);

Porque operator() del objeto redirige a constructor de su propio tipo.

 0
Author: Lexey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-18 09:16:49