passando functor como ponteiro de function

Eu estou tentando usar uma biblioteca C em um aplicativo C ++ e ter encontrado meu self na seguinte situação (eu sei meu C, mas eu sou relativamente novo em C ++). No lado C, tenho uma coleção de funções que usa um ponteiro de function como argumento. No lado do C ++ eu tenho objects com um functor que tem a mesma assinatura que o ponteiro de function necessário pela function C. Existe alguma maneira de usar o functor C ++ como um ponteiro de function para passar para a function C?

Você não pode passar diretamente um ponteiro para um object functor C ++ como um ponteiro de function para o código C (ou mesmo para o código C ++).

Além disso, para transmitir portavelmente um retorno de chamada para o código C, ele precisa ser pelo menos declarado como uma function de não membro extern "C" . Pelo menos, porque algumas APIs requerem convenções de chamada de function específicas e, portanto, modificadores de declaração adicionais.

Em muitos ambientes, C e C ++ têm as mesmas convenções de chamada e diferem apenas no nome mangling, portanto, qualquer function global ou membro estático funcionará. Mas você ainda precisa envolver a chamada para operator() em uma function normal.

  • Se o seu functor não tiver estado (é um object apenas para satisfazer alguns requisitos formais, etc.):

     class MyFunctor { // no state public: MyFunctor(); int operator()(SomeType &param) const; } 

    você pode escrever uma function externa normal “C” que cria o functor e executa seu operador ().

     extern "C" int MyFunctorInC(SomeType *param) { static MyFunctor my_functor; return my_functor(*param); } 
  • Se o seu functor tiver estado, por exemplo:

     class MyFunctor { // Some fields here; public: MyFunctor(/* some parameters to set state */); int operator()(SomeType &param) const; // + some methods to retrieve result. } 

    e a function de retorno de chamada C usa algum tipo de parâmetro de estado do usuário (geralmente void *):

     void MyAlgorithmInC(SomeType *arr, int (*fun)(SomeType *, void *), void *user_state); 

    você pode escrever uma function externa normal “C” que lança seu parâmetro de estado para o seu object functor:

     extern "C" int MyFunctorInC(SomeType *param, void *user_state) { MyFunctor *my_functor = (MyFunctor *)user_state; return (*my_functor)(*param); } 

    e usá-lo assim:

     MyFunctor my_functor(/* setup parameters */); MyAlgorithmInC(input_data, MyFunctorInC, &my_functor); 
  • Caso contrário, a única maneira normal de fazê-lo (normal como em “sem gerar código de máquina em tempo de execução” etc.) é usar algum armazenamento local estático (global) ou thread para passar o functor a uma function “C” externa. Isso limita o que você pode fazer com o seu código e é feio, mas vai funcionar.

Eu encontrei esta ” jóia ” usando o google. Aparentemente possível, mas com certeza não o recomendaria. Link direto para exemplo de código fonte.

A function de retorno de chamada AC escrita em C ++ deve ser declarada como uma function extern "C" – portanto, usar um functor diretamente está fora. Você precisará escrever algum tipo de function de wrapper para usar como aquele callback e fazer com que aquele wrapper chame o functor. Naturalmente, o protocolo de retorno de chamada precisará ter alguma forma de passar o contexto para a function para que ele possa chegar ao functor ou a tarefa se torne bastante complicada. A maioria dos esquemas de retorno de chamada tem um jeito de passar o contexto, mas eu trabalhei com alguns que não têm cérebro morto.

Veja esta resposta para mais alguns detalhes (e procure nos comentários por evidências que o retorno de chamada deve ser extern "C" e não apenas uma function de membro estático):

  • C ++ usando o método de class como um tipo de ponteiro de function

Claro que não. A assinatura da sua function C leva um argumento como function.

 void f(void (*func)()) { func(); // Only void f1(), void F2(), .... } 

Todos os truques com functores são usados ​​por funções de modelo :

 template void f (Func func) { func(); // Any functor } 

Eu não acho que você pode: operator() em um object de function é realmente uma function de membro, e C não sabe nada sobre isso.

O que você deve ser capaz de usar são funções C ++ gratuitas ou funções estáticas de classs.

O GCC permite converter pointers de function de membro em pointers de function simples (o primeiro argumento da function chamado pelo ponteiro de function simples é this ).

Confira o respectivo link no manual .

Isso requer o -Wno-pmf-conversions para silenciar o respectivo aviso para o recurso decididamente não padrão. Muito conveniente para a interface de bibliotecas de estilo C com programação no estilo C ++. Quando o ponteiro de function de membro é uma constante, isso nem precisa gerar nenhum código: a API usaria essa ordem de argumento de qualquer maneira.

Se você já tem um functor, achatar o functor dessa maneira provavelmente significará achatar seu operator() , dando-lhe uma function que tem que ser chamada com um próprio ponteiro de class functor como seu primeiro argumento. O que não necessariamente ajuda muito, mas pelo menos tem binding C.

Mas, pelo menos, quando você não está passando por functores, isso é útil e fornece uma substituição de enlace C não-sem-sentido para std::mem_fn de .

Depende se este é um método estático ou de instância, se é estático, então você pode passar pela function como className :: functionName, se é um método de instância é mais justo, porque obviamente você precisa amarrar a uma certa instância mas não pode fazer da mesma maneira que você faria com delegates em C # etc.

A melhor maneira que eu encontrei de fazer isso é criar uma class holding que é instanciada com a instância do object, bem como o ponteiro de function, a class holding, em seguida, pode invocar a function diretamente.

Eu diria que não, porque um functor de C ++ tem um operador sobrecarregado () que é uma function de membro e, portanto, exigiria um ponteiro de function de membro. Esse é um tipo de dados totalmente diferente de um ponteiro de function C normal, já que ele não pode ser chamado sem uma instância da class. Você precisaria passar uma function normal ou uma function de membro estático para a biblioteca C. Como um operador sobrecarregado () não pode ser estático, você não pode fazê-lo. Você precisaria passar à biblioteca C uma function normal, não-membro ou function de membro estático, a partir da qual você pode invocar o functor C ++.

Hm, talvez você possa escrever uma function de modelo livre que envolva seus objects de function. Se todos tiverem a mesma assinatura, isso deve funcionar. Assim (não testado):

 template int function_wrapper(int a, int b) { T function_object_instance; return funcion_object_instance( a, b ); } 

Isso serve para todas as funções que levam dois inteiros e retornam um int.

Muitas APIs C que recebem retornos de chamada de ponteiro de function possuem um parâmetro void * para o estado do usuário. Se você tem um desses, você está com sorte – você pode usar uma function C exterm que trata os dados do usuário como algum tipo de referência ou chave para procurar o functor, então executá-lo.

Caso contrário, não.

Intereting Posts