2011-07-07 22 views

Respuesta

140

std::bind es para partial function application.

Es decir, supongamos que tiene un objeto función f que tiene 3 argumentos:

f(a,b,c); 

usted quiere un nuevo objeto función que sólo toma dos argumentos, define como:

g(a,b) := f(a, 4, b); 

g es una "aplicación parcial" de la función f: el argumento del medio ya ha sido especificado, y quedan dos por recorrer.

Se puede utilizar para obtener std::bindg:

auto g = bind(f, _1, 4, _2); 

Esto es más conciso que en realidad escribir una clase funtor para hacerlo.

Hay más ejemplos en el artículo al que se vincula. Generalmente lo usa cuando necesita pasar un functor a algún algoritmo. Usted tiene una función o un functor que casi hace el trabajo que desea, pero es más configurable (es decir, tiene más parámetros) que el algoritmo utiliza. Por lo que ates argumentos para algunos de los parámetros, y dejar el resto para el algoritmo para rellenar:

// raise every value in vec to the power of 7 
std::transform(vec.begin(), vec.end(), some_output, std::bind(std::pow, _1, 7)); 

Aquí, pow toma dos parámetros y puede elevar a cualquier poder, pero lo único que importa es el aumento a la potencia de 7.

Como un uso ocasional, que no es de aplicación función parcial, bind también se puede volver a ordenar los argumentos a una función:

auto memcpy_with_the_parameters_in_the_right_flipping_order = bind(memcpy, _2, _1, _3); 

no recomiendo usarlo sólo porque no le gusta la API, pero tiene potenciales usos prácticos, por ejemplo, debido a que:

not2(bind(less<T>, _2, _1)); 

es una función igual menos-que-o-(suponiendo un orden total, bla, bla). Este ejemplo normalmente no es necesario ya que ya existe un std::less_equal (usa el operador <= en lugar de <, por lo que si no son consistentes, entonces puede necesitar esto, y es posible que también necesite visitar al autor de la clase con un cluestick). Sin embargo, es el tipo de transformación que surge si estás usando un estilo funcional de programación.

+10

También es práctico para las devoluciones de llamada a funciones miembro: 'miThread = impulso :: hilo (boost :: bind (y MyClass :: threadMain, este))' – rlduffy

+10

Buena explicación de bind. Pero ¿qué pasa con 'std :: function'? – RedX

+4

Tu ejemplo 'pow' no se compila. Como 'pow' es una función sobrecargada, debe especificar manualmente qué sobrecarga. El enlace no puede dejar que sea deducido por la persona que llama del funtor resultante. P.ej. 'std :: transform (vec.begin(), vec.end(), out.begin(), std :: bind ((double (*) (double, int)) std :: pow, _1, 7)) ; ' –

7

std :: bind se votó en la biblioteca después de la propuesta para incluir boost boost, principalmente es la especialización de funciones parciales donde se pueden corregir algunos parámetros y cambiar otros on fly. Ahora esta es la manera de hacer lambdas en C++.Como respondió Steve Jessop

Ahora que C++ 11 admite funciones lambda, no siento la tentación de usar std :: bind nunca más. Prefiero usar currying (especialización parcial) con la función de idioma que la función de biblioteca.

std :: los objetos de función son funciones polimórficas. La idea básica es poder hacer referencia a todos los objetos invocables de forma intercambiable.

Te gustaría señalar que estos dos enlaces para más detalles:

funciones lambda en C++ 11: http://www.nullptr.me/2011/10/12/c11-lambda-having-fun-with-brackets/#.UJmXu8XA9Z8

entidad invocable en C++: http://www.nullptr.me/2011/05/31/callable-entity/#.UJmXuMXA9Z8

+3

'std :: bind' nunca existió sin lambdas: ambas características se introdujeron en C++ 11.Tuvimos 'bind1st' y' bind2nd' que eran versiones demacradas de C++ 11 bind. –

5

lo usé mucho tiempo volver para crear un grupo de subprocesos de plugin en C++; Dado que la función estaba tomando tres parámetros que se pueden escribir como este

Suponga que su método tiene la firma:

int CTask::ThreeParameterTask(int par1, int par2, int par3) 

Para crear un objeto de función para unir los tres parámetros que se pueden hacer como esto

// a template class for converting a member function of the type int function(int,int,int) 
//to be called as a function object 
template<typename _Ret,typename _Class,typename _arg1,typename _arg2,typename _arg3> 
class mem_fun3_t 
{ 
public: 
    explicit mem_fun3_t(_Ret (_Class::*_Pm)(_arg1,_arg2,_arg3)) 
     :m_Ptr(_Pm) //okay here we store the member function pointer for later use 
    {} 

    //this operator call comes from the bind method 
    _Ret operator()(_Class *_P, _arg1 arg1, _arg2 arg2, _arg3 arg3) const 
    { 
     return ((_P->*m_Ptr)(arg1,arg2,arg3)); 
    } 
private: 
    _Ret (_Class::*m_Ptr)(_arg1,_arg2,_arg3);// method pointer signature 
}; 

Ahora, para enlazar los parámetros, tenemos que escribir una función de enlace. Por lo tanto, aquí va:

template<typename _Func,typename _Ptr,typename _arg1,typename _arg2,typename _arg3> 
class binder3 
{ 
public: 
    //This is the constructor that does the binding part 
    binder3(_Func fn,_Ptr ptr,_arg1 i,_arg2 j,_arg3 k) 
     :m_ptr(ptr),m_fn(fn),m1(i),m2(j),m3(k){} 


     //and this is the function object 
     void operator()() const 
     { 
      m_fn(m_ptr,m1,m2,m3);//that calls the operator 
     } 
private: 
    _Ptr m_ptr; 
    _Func m_fn; 
    _arg1 m1; _arg2 m2; _arg3 m3; 
}; 

Y, una función de ayuda para utilizar la clase binder3 - bind3:

//a helper function to call binder3 
template <typename _Func, typename _P1,typename _arg1,typename _arg2,typename _arg3> 
binder3<_Func, _P1, _arg1, _arg2, _arg3> bind3(_Func func, _P1 p1,_arg1 i,_arg2 j,_arg3 k) 
{ 
    return binder3<_Func, _P1, _arg1, _arg2, _arg3> (func, p1,i,j,k); 
} 

y aquí nos cómo llamamos

F3 f3 = PluginThreadPool::bind3(PluginThreadPool::mem_fun3( 
      &CTask::ThreeParameterTask), task1,2122,23); 

Nota: f3(); llamará al método task1-> ThreeParameterTask (21,22,23);

Para detalles más morbosos ->http://www.codeproject.com/Articles/26078/A-C-Plug-in-ThreadPool-Design

3

Uno de los usos principales de std :: función y std :: bind es como punteros a funciones de seguridad. Hay muchos artículos en la web que explican cómo los punteros a las funciones son útiles en C/C++. Por ejemplo, son útiles para implementar el mecanismo de devolución de llamada. Es decir, tiene alguna función que tardará mucho tiempo en ejecutarse pero no desea esperar a que vuelva, entonces puede ejecutar esa función en un hilo separado y darle un puntero de función que devolverá la llamada una vez que se complete .

Aquí hay un código de ejemplo para el uso de esta:

class MyClass { 
private: 
    //just shorthand to avoid long typing 
    typedef std::function<void (float result)> CallbackType; 

    //this function takes long time 
    void longRunningFunction(CallbackType callback) 
    { 
     //do some long running task 
     //... 
     //callback to return result 
     callback(result); 
    } 

    //this function gets called by longRunningFunction after its done 
    void afterCompleteCallback(float result) 
    { 
     std::cout << result; 
    } 

public: 
    int longRunningFunctionAsync() 
    { 
     //create callback - this equivalent of safe function pointer 
     auto callback = std::bind(&MyClass::afterCompleteCallback, 
      this, std::placeholders::_1); 

     //normally you want to start below function on seprate thread, 
     //but for illustration we will just do simple call 
     longRunningFunction(callback); 
    } 
}; 
Cuestiones relacionadas