Вот типичное использование указателей на функции в C. Я хотел бы сделать нечто подобное в Fortran. У меня есть некоторые идеи, но я хотел бы знать, есть ли какой-то канонический способ сделать это.
Указатели и контексты функций, переданные пользователем, сохраняются, а затем вызываются позже.
typedef PetscErrorCode (*TSIFunction)(TS,PetscReal,Vec,Vec,Vec,void*);
PetscErrorCode TSSetIFunction(TS ts,Vec res,TSIFunction f,void *ctx);
Функция пользователя вызывается обратно с использованием их контекста в разное время.
В PETSc также интенсивно используются таблицы указателей на строку -> функция. Все это плагин, так что пользователь может зарегистрировать свои собственные реализации, и они первоклассные.
#define PCGAMG "gamg"
PCRegisterDynamic(PCGAMG ,path,"PCCreate_GAMG",PCCreate_GAMG);
Это регистрирует процедуру создания в «FList», затем PCSetFromOptions () предлагает возможность выбрать этот метод в сравнении с любым другим выбором. Если система поддерживает динамическую загрузку, вы можете пропустить зависимость времени компиляции от символа PCCreate_GAMG и просто передать NULL, тогда этот символ будет найден в общей библиотеке во время выполнения.
Обратите внимание, что это один шаг за пределы «фабрики», это инверсия управляющего устройства, похожая на то, что Мартин Фаулер называет «локатором услуг».
Примечание: это произошло в моей личной переписке с Джедом Брауном, где он задал мне этот вопрос. Я решил передать его на аутсорсинг и посмотреть, какие ответы могут дать люди.
В вашем вопросе есть много того, что я предполагаю, это специфичный для PETSc язык (с которым я незнаком), поэтому здесь может быть морщина, которую я не совсем понимаю, но, возможно, это все еще будет полезно, чтобы вы началось.
По сути, вы должны определить интерфейс для процедуры, а затем вы можете передать указатель на функцию, которая следует за этим интерфейсом. Следующий код показывает пример. Во-первых, есть модуль, который определяет интерфейс и показывает быстрый пример фрагмента кода, который будет выполнять подпрограмму, предоставленную пользователем, который следует этому интерфейсу. Далее идет программа, которая показывает, как пользователь будет использовать этот модуль и определить функцию, которая будет выполняться.
источник
PROCEDURE(function_template), POINTER :: func
внутри.void*
, пользователю приходится писать интерфейсы для библиотечных функций. Если вы реализуете библиотеку в C, этого достаточно, но если вы внедряете в Fortran, вы должны убедиться, что компилятор никогда не увидит «фиктивный» ИНТЕРФЕЙС библиотеки одновременно с ИНТЕРФЕЙСОМ пользователя.void*
в Фортране являетсяtransfer
метод. Смотрите здесь для примера использования. Другие 3 подхода, помимоtransfer
метода, представляют собой «рабочие массивы», «конкретный производный тип вместоvoid *
» и используют локальные для модуля переменные модуля.transfer
к бессмысленному типу (character (len=1), allocatable
) только для вызова функции.