[C ++] Adaptador de objeto de función y su principio subyacente

Adaptador de objeto de función

bind1st bind2nd

El adaptador de objeto de función se utiliza para ampliar la función del objeto de función y proporcionar un método para pasar parámetros adicionales.

Por ejemplo, ahora tengo un predicado unario:

class Pred {
    
    
   public:
    bool operator()(int a) {
    
    
        // ...
    }
};

Ahora llame a un algoritmo, el algoritmo usará este predicado unario.

algorithm(..., ..., Pred());

Pero al mismo tiempo, esperamos que este predicado pueda implementar una función adicional, y esta función depende de un parámetro pasado temporalmente.

Entonces se cambió la realización del predicado:

bool operator()(int a, string b){
    
    
    // ...
}

Pero este nuevo parámetro bno se puede algorithm(..., ..., Pred());pasar durante la llamada .

El adaptador se utilizará en este momento.

Los pasos básicos:

Deje que la clase de este predicado herede una plantilla de clase binary_function<{参数1类型, 参数2类型, 返回值类型}>y, al mismo tiempo, constmodifique el predicado como una función constante (en realidad, un método que anula la clase principal).

Tenga en cuenta que la herencia de predicados unariosunary_functionHerencia de predicado binariobinary_function

class Pred: public binary_function<int, string, bool>{
    
    
   public:
    bool operator()(int a, string b) const {
    
    
        // ...
    }
};

Luego, al llamar al algoritmo,

A través de una función bind2nd, vincule el segundo parámetro al adaptador y pase este parámetro al mismo tiempo.

algorithm(..., ..., bind2nd(Pred(), "param");

Además, también podemos usar funciones para bind1stvincular el primer parámetro al adaptador.En este momento, los parámetros adicionales se pasarán en la posición del primer parámetro y el algoritmo usará el segundo parámetro.

bind1st no solo puede expandir predicados unarios, sino también unir predicados binarios y convertirlos en predicados unarios

Por ejemplo, el siguiente código significa un predicado donde x> 5:

bind2nd(greater<int>(), 1);

Implementación de bajo nivel

En cuanto al adaptador de objeto de función, si no comprende su principio de implementación, a menudo es difícil recordar los pasos a la vez.

Por ejemplo, ¿por qué desea heredar, por qué la lista de tipos de plantilla <{参数1类型, 参数2类型, 返回值类型}>,

Para otro ejemplo, bind1st¿qué trabajo hiciste?

Dado que este semestre ha estado trabajando en cosas en la dirección web, es inevitable escribir js, y escribir js inevitablemente entrará en contacto con el alcance de la cadena.

Aunque esto es poderoso y flexible, también es difícil de entender y aplicar realmente. Aunque pisé los boxes por todas partes, también me entrenó la habilidad correspondiente.

Deja de decir tonterías y entra en el tema.

Cuando lo vi bind2nd(Pred(), "param"), inmediatamente pensé en empaquetar. Al escribir js, es inevitable envolver algunas cosas y expandir funciones.

Al leer el código de implementación en la biblioteca, descubrí que probablemente hizo estas cosas, que es similar a lo que pensé:

Devuelve un cierre, coloca el objeto de función y los parámetros adicionales en el alcance externo y pasa parámetros adicionales cuando se llama al algoritmo.

Descrito con js de la siguiente manera:

function bind2nd(fun, extraParam){
    
    
    return function(param){
    
    
        return fun(param, extraParam);
    }
}

En C ++, devuelve una instancia de una clase. Esta instancia se construye con un objeto de función y parámetros adicionales, y luego () se reescribe dentro para envolver nuestro objeto de función.

De hecho, ya está muy claro aquí, pero desde entonces he estado pensando por qué hay un paso de herencia y por qué herencia.

De hecho, js es el final de la escritura aquí, pero C ++ es un lenguaje de tipado estático. En js, puede pasar parámetros y devolver casualmente. Lo indefinido, nulo, etc., debe estar claramente definido en C ++.

Entonces, de hecho, esta herencia se trata de tipos de parámetros y tipos de valor de retorno.

Después de analizar el código de implementación nuevamente, encontré que él hizo estas tareas:

La clase que queremos heredar binary_functiones una plantilla de clase, que se instancia después de la herencia bind2nd(Pred(), "param").

En este momento, la clase principal se usingespecifica mediante el alias, y se registran los parámetros y tipos de valor de retorno Estos valores registrados bind2ndse utilizan durante el empaquetado y se utilizan como () reescritura.

Dos clases, una para la grabación de tipos y otra para el empaquetado de llamadas, solo funcionan con el adaptador para completar el trabajo.

Probablemente lo escriba a mano:

Esta es probablemente la implementación de la clase contenedora:

tmelate<class funType>
class bind2nd {
    
    
   public:
    using p1Type = funType::p1Type;
    using p2Type = funType::p2Type;
    using resultType = funType::resultType;
    binary_function(funType& fun, p2Type extraParam): fun(fun), extraParam(extraParam) {
    
    };
    resultType operator()(const p1Type& arg) const {
    
    
      return fun(arg, value);
    }
   protected:
    funType fun;
    p2Type extraParam; // the right operand
};

Esta es probablemente la implementación de la clase que queremos heredar:

template<class arg1, class arg2, class result>
class binary_function {
    
    
   public:
    using p1Type = typename arg1;
    using p2Type = typename arg2;
    using resultType = typename result; 
};

Supongo que te gusta

Origin blog.csdn.net/qq_16181837/article/details/106738651
Recomendado
Clasificación