Eu não gosto de ter caixas mágicas espalhadas por todo o meu código ... como exatamente essas duas classes funcionam para permitir que basicamente qualquer função seja mapeada para um objeto de função, mesmo se a função <> tiver um parâmetro completamente diferente definido para aquele que estou passando boost::bind
Ele ainda funciona com diferentes convenções de chamada (ou seja, os métodos de membro estão __thiscall
sob VC, mas as funções "normais" são geralmente __cdecl
ou __stdcall
para aqueles que precisam ser compatíveis com C.
c++
boost
boost-bind
boost-function
Fire Lancer
fonte
fonte
Respostas:
boost::function
permite que qualquer coisa com umoperator()
com a assinatura correta seja vinculado como parâmetro, e o resultado de sua vinculação pode ser chamado com um parâmetroint
, para que possa ser vinculadofunction<void(int)>
.É assim que funciona (esta descrição aplica-se igualmente a
std::function
):boost::bind(&klass::member, instance, 0, _1)
retorna um objeto como estestruct unspecified_type { ... some members ... return_type operator()(int i) const { return instance->*&klass::member(0, i); }
em que
return_type
eint
são inferidos da assinatura deklass::member
, e o ponteiro de função e o parâmetro vinculado são de fato armazenados no objeto, mas isso não é importanteAgora,
boost::function
não faz nenhuma verificação de tipo: ele pegará qualquer objeto e qualquer assinatura que você fornecer em seu parâmetro de modelo e criará um objeto que pode ser chamado de acordo com sua assinatura e chamará o objeto. Se isso for impossível, é um erro de compilação.boost::function
é na verdade um objeto como este:template <class Sig> class function { function_impl<Sig>* f; public: return_type operator()(argument_type arg0) const { return (*f)(arg0); } };
de onde
return_type
eargument_type
são extraídosSig
ef
são alocados dinamicamente no heap. Isso é necessário para permitir que objetos completamente não relacionados com tamanhos diferentes sejam vinculadosboost::function
.function_impl
é apenas uma classe abstratatemplate <class Sig> class function_impl { public: virtual return_type operator()(argument_type arg0) const=0; };
A classe que faz todo o trabalho é uma classe concreta derivada de
boost::function
. Existe um para cada tipo de objeto que você atribuiboost::function
template <class Sig, class Object> class function_impl_concrete : public function_impl<Sig> { Object o public: virtual return_type operator()(argument_type arg0) const=0 { return o(arg0); } };
Isso significa, no seu caso, a atribuição para impulsionar a função:
function_impl_concrete<void(int), unspecified_type>
(que é o tempo de compilação, é claro)Quando você chama o objeto de função, ele chama a função virtual de seu objeto de implementação, que direcionará a chamada para sua função original.
AVISO LEGAL: Observe que os nomes nesta explicação são deliberadamente inventados. Qualquer semelhança com pessoas ou personagens reais ... você sabe disso. O objetivo era ilustrar os princípios.
fonte
arg0) const=0 { return...
... Eu nunca vi isso antes. Eu encontrei um exemplo que não funciona em um fórum onde uma mensagem de acompanhamento vinculada ao faq C ++ explicando que uma função virtual pura poderia ter um corpo, mas não consigo compilar nenhum código usando uma sintaxe como essa (clang & gcc).=0;
com o corpo dado posteriormente (por exemplo,void Base::Blah() { /* ... */ }
) ... Estou perguntando especificamente sobre a notação usada acima; Suponho que seja apenas um erro de digitação.