Respostas:
std::bind
é para aplicação de função parcial .
Ou seja, suponha que você tenha um objeto de função f
que use 3 argumentos:
f(a,b,c);
Você deseja um novo objeto de função que use apenas dois argumentos, definidos como:
g(a,b) := f(a, 4, b);
g
é uma "aplicação parcial" da função f
: o argumento do meio já foi especificado e há dois a serem deixados.
Você pode usar std::bind
para obter g
:
auto g = bind(f, _1, 4, _2);
Isso é mais conciso do que realmente escrever uma classe functor para fazê-lo.
Existem outros exemplos no artigo ao qual você vincula. Você geralmente o usa quando precisa passar um functor para algum algoritmo. Você tem uma função ou functor que quase faz o trabalho que deseja, mas é mais configurável (ou seja, possui mais parâmetros) do que o algoritmo usa. Então, você vincula argumentos a alguns dos parâmetros e deixa o restante para o algoritmo preencher:
// raise every value in vec to the power of 7
std::transform(vec.begin(), vec.end(), some_output, std::bind(std::pow, _1, 7));
Aqui, são pow
necessários dois parâmetros e podem aumentar para qualquer potência, mas tudo o que importa é elevar a potência de 7.
Como uso ocasional que não é aplicação parcial de função, bind
também é possível reordenar os argumentos para uma função:
auto memcpy_with_the_parameters_in_the_right_flipping_order = bind(memcpy, _2, _1, _3);
Não recomendo usá-lo apenas porque você não gosta da API, mas ela tem possíveis usos práticos, por exemplo, porque:
not2(bind(less<T>, _2, _1));
é uma função menor ou igual (assumindo uma ordem total, blá blá). Esse exemplo normalmente não é necessário, pois já existe um std::less_equal
(ele usa o <=
operador e não <
, portanto, se eles não são consistentes, você pode precisar disso e também visitar o autor da classe com um cluestick). É o tipo de transformação que surge se você estiver usando um estilo funcional de programação.
std::function
?
pow
exemplo não é compilado. Como pow
é uma função sobrecarregada, é necessário especificar manualmente qual sobrecarga. A ligação não pode ser deduzida pelo responsável pela chamada do functor resultante. Exemplostd::transform(vec.begin(), vec.end(), out.begin(), std::bind((double (*)(double, int))std::pow, _1, 7));
std::bind
vem junto com o this
uso como o segundo argumento. Você pode elaborar esse caso de uso?
std::placeholders::_1
. Demorei um pouco para descobrir por que isso não estava sendo compilado.
Um dos principais usos de std :: function e std :: bind é como ponteiros de função mais generizados. Você pode usá-lo para implementar o mecanismo de retorno de chamada. Um dos cenários populares é que você tem alguma função que levará muito tempo para ser executada, mas não deseja esperar que ela retorne. Você pode executar essa função em um thread separado e fornecer um ponteiro de função que retorno de chamada após a conclusão.
Aqui está um código de exemplo de como usar isso:
class MyClass {
private:
//just shorthand to avoid long typing
typedef std::function<void (float result)> TCallback;
//this function takes long time
void longRunningFunction(TCallback 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);
}
};
std :: bind foi votado na biblioteca após a proposta para incluir o boost bind, principalmente é a especialização parcial da função, onde é possível corrigir alguns parâmetros e alterar outros rapidamente. Agora, essa é a maneira da biblioteca fazer lambdas em C ++. Respondida por Steve Jessop
Agora que o C ++ 11 suporta funções lambda, não sinto mais nenhuma tentação de usar std :: bind. Prefiro usar currying (especialização parcial) com recurso de idioma do que com recurso de biblioteca.
Os objetos std :: function são funções polimórficas. A idéia básica é ser capaz de se referir a todos os objetos que podem ser chamados de forma intercambiável.
Eu indicaria esses dois links para mais detalhes:
Funções Lambda no C ++ 11: http://www.nullptr.me/2011/10/12/c11-lambda-having-fun-with-brackets/#.UJmXu8XA9Z8
Entidade que pode ser chamada em C ++: http://www.nullptr.me/2011/05/31/callable-entity/#.UJmXuMXA9Z8
std::bind
nunca existiu sem lambdas - esses dois recursos foram introduzidos no C ++ 11. Nós tínhamos bind1st
e bind2nd
quais eram as versões emaciadas do C ++ 11 bind.
Usei muito tempo para criar um pool de threads de plug-in em C ++; Como a função estava usando três parâmetros, você pode escrever assim
Suponha que seu método tenha a assinatura:
int CTask::ThreeParameterTask(int par1, int par2, int par3)
Para criar um objeto de função para ligar os três parâmetros, você pode fazer assim
// 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
};
Agora, para vincular os parâmetros, precisamos escrever uma função do fichário. Então, aqui vai:
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;
};
E, uma função auxiliar para usar a classe 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);
}
e aqui nos como chamá-lo
F3 f3 = PluginThreadPool::bind3( PluginThreadPool::mem_fun3(
&CTask::ThreeParameterTask), task1,2122,23 );
Nota: f3 (); chamará o método task1-> ThreeParameterTask (21,22,23);
Para obter detalhes mais sangrentos -> http://www.codeproject.com/Articles/26078/AC-Plug-in-ThreadPool-Design
myThread=boost::thread(boost::bind(&MyClass::threadMain, this))