Aqui está um uso típico de ponteiros de função em C. Eu gostaria de fazer algo semelhante no Fortran. Tenho algumas idéias, mas gostaria de saber se existe alguma maneira canônica de fazer isso.
Os ponteiros de função e os contextos transmitidos pelo usuário são armazenados e depois chamados posteriormente.
typedef PetscErrorCode (*TSIFunction)(TS,PetscReal,Vec,Vec,Vec,void*);
PetscErrorCode TSSetIFunction(TS ts,Vec res,TSIFunction f,void *ctx);
A função do usuário é chamada de volta usando seu contexto em vários momentos posteriores.
No PETSc, eles também usam muito as tabelas de ponteiros de função string>. Tudo é um plugin, para que o usuário possa registrar suas próprias implementações e elas são de primeira classe.
#define PCGAMG "gamg"
PCRegisterDynamic(PCGAMG ,path,"PCCreate_GAMG",PCCreate_GAMG);
Isso registra a rotina de criação em um "FList" e, em seguida, PCSetFromOptions () oferece a capacidade de escolher esse método em comparação com qualquer uma das outras opções. Se o sistema suportar carregamento dinâmico, você poderá pular a dependência do símbolo PCCreate_GAMG em tempo de compilação e passar NULL, em seguida, o símbolo será procurado na biblioteca compartilhada em tempo de execução.
Observe que este passo além de uma "fábrica", é uma inversão do dispositivo de controle semelhante ao que Martin Fowler chama de "localizador de serviço".
Nota: isso surgiu em minha correspondência particular com Jed Brown, onde ele me fez essa pergunta. Decidi terceirizá-lo e ver quais respostas as pessoas podem apresentar.
Há muito do que eu acho que é uma linguagem específica do PETSc na sua pergunta (com a qual eu não estou familiarizado), então pode haver uma ruga aqui que eu não entendo direito, mas talvez isso ainda seja útil para você começado.
Basicamente, você precisa definir a interface para o procedimento e, em seguida, pode passar um ponteiro para uma função que segue essa interface. O código a seguir mostra um exemplo. Primeiro, existe um módulo que define a interface e mostra um exemplo rápido de um pedaço de código que executaria a rotina fornecida pelo usuário que segue essa interface. A seguir, é apresentado um programa que mostra como o usuário usaria esse módulo e definiria a função a ser executada.
fonte
PROCEDURE(function_template), POINTER :: func
internamente.void*
, o usuário acaba tendo que escrever interfaces para as próprias funções da biblioteca. Se você implementar a biblioteca em C, isso é suficiente, mas se você implementar no Fortran, precisará garantir que o compilador nunca veja o INTERFACE "fictício" da biblioteca ao mesmo tempo que o INTERFACE do usuário.void*
em Fortran é umtransfer
método. Veja aqui um exemplo de uso. As outras 3 abordagens além dotransfer
método são "matrizes de trabalho", "tipo derivado específico em vez devoid *
" e usam variáveis de módulo locais para o módulo.transfer
um tipo sem sentido (character (len=1), allocatable
) apenas para chamar a função.