2012-08-04 627 views
9

acabo read alguien llamada una clase con un constructor y un predicado operator() un :¿Cuál es la diferencia entre un predicado y un funcionador?

// Example 
class Foo { 
    public: 
    Foo(Bar); 
    bool operator()(Baz); 
    private: 
    Bar bar; 
}; 

Sin embargo, no he escuchado la palabra predicado se utiliza en este contexto antes. Yo llamaría a esto un funcionador . Para mí, un predicado sería algo del dominio de la lógica formal.

Esto plantea las siguientes preguntas:

  • Es ésta una palabra común para algo así como Foo?
  • ¿Se usan ambos términos indistintamente, o tienen un significado ligeramente diferente?
  • O
    • ¿El tipo de retorno (bool frente a otra cosa) tiene algo que ver con ella?
    • ¿Qué pasa con el operator() que es const?

Respuesta

22

Functor es un término que se refiere a una entidad que soporta un operador () en las expresiones (con cero o más parámetros), es decir, algo que se comporta sintácticamente como una función. Functor no es necesariamente un objeto de alguna clase con operator() sobrecargado. Los nombres de funciones comunes también son funtores. Aunque en algunos contextos se puede ver el término "functor" usado en un sentido más restringido y exclusivo: solo objetos de clase, pero no funciones ordinarias.

Un predicado es un tipo específico de funtor: un funtor que se evalúa como un valor booleano. No es necesariamente un valor del tipo bool, sino más bien un valor de cualquier tipo con semántica "booleana". Sin embargo, el tipo debe ser implícitamente convertible a bool.

+3

Agradable. En el sentido general, un functor es * cualquier objeto/artefacto que representa una función * por diseño. Si lo hace sintácticamente y/o con 'operator()' es azúcar. –

3

La clase mostrado es un funtor que implementa un predicado.

A predicate es una función booleana.

Acerca del operator() que no es const aquí: idealmente debería ser const, sí.

+0

La clase mostrada fue un ejemplo. Me pregunto si cada predicado es un funtor. ¿Qué restricciones se aplican, aparte de que el valor de retorno sea booleano? ¿Sería una función libre que devuelve 'bool' también un predicado? – bitmask

+0

Cada predicado es una función booleana, en un nivel adecuado de abstracción. Ciertamente, los predicados en Prolog no son funtores de C++ :-). Y así que sí, una función independiente puede ser (usado como) un predicado. Al mirar la pregunta a la que se vinculó (lo siento, no lo miré antes), no es un predicado puro, ya que tiene un efecto secundario. Idealmente, un predicado no tiene efectos secundarios, solo le dice si los argumentos cumplen alguna condición, generalmente que tienen alguna relación. –

2

Un predicado es un tipo especial de objeto de función. Vea esto excelente column por Nicolai Josuttis.Para citar:

Un objeto de función que devuelve un valor booleano es un predicado. Eso es lo que casi todos los tutoriales, libros y manuales escriben sobre los predicados de la STL. Esto, sin embargo, no es toda la historia.

Sin embargo, hay un requisito adicional de que es por desgracia no menciona en ningún manual o en el estándar de C++: Un predicado debe siempre devuelven el mismo resultado para el mismo valor.

O, en el lenguaje de C++: Debe declarar operador() en función miembro constante (y no jugar con mutable o cilindros). Por la misma razón, una copia de un predicado debe tener el mismo estado que el original.

La razón es que los algoritmos STL copiarán objetos de función, y la copia no debería afectar el resultado de aplicar los objetos de función.

template<typename Arg0> 
struct UnaryPredicate 
: 
    public std::function<bool(Arg0 const&)> 
{ 
    bool operator()(Arg0 const& a0) const 
    { 
     return // your code here 
    } 
}; 

template<typename Arg0, typename Arg1> 
struct BinaryPredicate 
: 
    public std::function<bool(Arg0 const&, Arg1 const&)> 
{ 
    bool operator()(Arg const& a0, Arg const& a1) const 
    { 
     return // your code here 
    } 
}; 
1

Como se ha dicho, un predicado es solo una directiva suministrada por el usuario para analizar algo en un estado booleano. Para que pueda tener las mismas dos cosas que hacen lo mismo ...

struct is_odd 
{ 
    is_odd() : count(0); 
    bool operartor() (int i) const { ++count; return (i % 2) == 1; } 

private 
    int count; 
} 

Y ...

bool isOdd(int i) { return (i % 2) == 1; } 

Entonces, ¿qué es tan especial sobre el funtor? ¡Mantiene el estado si lo deseas! Eso significa que, si bien estas dos líneas de código hacen lo mismo (suponiendo que v es un vector, con valores de 0 - 9) ...

for_each(v.begin(), v.end(), isOdd); //using C-style function pointer 

Y ...

is_odd fn = for_each(v.begin(), v.end(), is_odd); //using functor 

Sólo con la segundo caso de uso puede entonces llamar ...

int calls = fn.count; 

Eso se debe a que for_each (así como otras funciones de algoritmo STL) devuelve el funtor se utiliza al final, por lo que ahora el estado final se puede consultar.

Otra cosa interesante a tener en cuenta es que en el segundo caso, estamos utilizando lo que se llama un objeto "anónimo".

Cuestiones relacionadas