2013-03-07 2 views
5

Я пишу код в Fortran 2003, который делает много линейной алгебры с разреженными матрицами. Я пытаюсь использовать некоторые из более абстрактных функций нового стандарта, поэтому у меня есть более простые программы без слишком много повторяющегося кода.Политизм во время выполнения в fortran 2003

У меня есть процедура solver, которая принимает в матрице, некоторые векторы, допуск для используемого итерационного метода и т. Д. Я передаю ему указатель на процедуру, называемую matvec; matvec - это подпрограмма, которую мы используем для умножения матричных векторов.

Проблема в том, что иногда matvec - это процедура, которая принимает дополнительные аргументы colorlist, color1, color2 над обычными, отправленными на эту процедуру. Я могу думать о нескольких способах борьбы с этим.

Первая идея: определить два разных абстрактных интерфейса matvec1, matvec2 и два разных решателя. Это работает, но это означает дублирование некоторого кода, чего я пытаюсь избежать.

Еще одна идея: сохранить тот же абстрактный интерфейс matvec, и сделать дополнительные аргументы , color1, color2 необязательными. Это означает, что они становятся необязательными в каждой процедуре matvec - даже для тех, для которых они не являются необязательными, и для процедур, где они даже не используются вообще. Довольно уверен, что я пойду в ад, если я это сделаю.

Я могу думать о множестве других менее оптимальных решений. Я бы хотел внести свой вклад в это - я уверен, что есть какой-то элегантный способ сделать это, я просто не уверен, что это такое.

ответ

5

Вопрос в том, должны ли дополнительные аргументы передаваться каждый раз при вызове процедуры (поскольку они меняются между двумя вызовами), или они могут быть инициализированы в какой-то момент, а затем просто используются в функции. В более позднем случае вы можете создать класс с абстрактным интерфейсом, который определяет вашу подпрограмму matvec с основными аргументами. Затем вы можете расширить этот класс более специализированными, которые могут содержать дополнительные параметры. Они все равно должны будут определить один и тот же интерфейс matvec в качестве родительского класса (с тем же списком аргументов), но они могут использовать дополнительные значения, хранящиеся в них, когда вызывается их процедура matvec.

Вы найдете подробный пример in this answer для аналогичного случая (ищите второй пример, показывающий module rechercheRacine).

2

Вместо передачи указателя процедуры в качестве явного аргумента, вы могли бы поставить различные matvec процедуры за общий интерфейс:

interface matvec 
    module procedure matvec1, matvec2 
end interface 

Тогда ваша solver процедура может просто использовать общее имя с или без дополнительных аргументов , Такой же подход может быть, конечно, проявлять осторожность при использовании предлагаемого подхода Балинта определения в solver в качестве производного типа с процедурами типа переплета:

type :: solver 
    real, allocatable :: matrix(:,:), v1(:), v2(:) 
contains 
    procedure, pass :: matvec1 
    procedure, pass :: matvec2 
    generic :: matvec => matvec1, matvec2 
end type 

Основное отличие заключается в том, что это не использует полиморфизм, чтобы определить правильную процедуру чтобы вызвать, а скорее характеристики фиктивных аргументов.

Я не уверен в ваших намерениях для указателя процедуры; если вы хотите изменить свою цель во время выполнения (или, возможно, присвоить определенный статус своему неопределенному статусу), то указатели являются единственным способом, и все цели должны соответствовать одному и тому же абстрактному интерфейсу.Если вместо этого вам просто нужно выбрать одну из нескольких процедур на основе своих аргументов, вы можете использовать интерфейс (мой пример) или перегрузку (пример Bálint). Каждое расширение типа может распространять унаследованное связывание generic с новыми процедурами или перегружать унаследованное специфическое связывание.

Смежные вопросы