интерфейсные процедуры с привязкой к типу на Фортране

Я пытаюсь определить процедуру interfaced как процедуру с привязкой к типу в определении Fortran type, но, похоже, она работает не так, как можно было бы ожидать. Рассмотрим следующий модуль:

module example_module
implicit none
private

interface add_them
  module procedure add_them_integer,add_them_real
end interface add_them

type, public :: foo
  integer, private :: a=1,b=2
  real, private :: c=4.,d=5.
contains
  procedure, public :: add => add_them
end type foo

contains
subroutine add_them_integer(self,x)
class(foo), intent(in) :: self
integer, intent(in) :: x
print *,self%a+self%b+x
end subroutine add_them_integer

subroutine add_them_real(self,x)
class(foo), intent(in) :: self
real, intent(in) :: x
print *,self%c+self%d+x
end subroutine add_them_real
end module example_module

и соответствующая программа, использующая модуль:

program example
use example_module
implicit none
type(foo) :: foofoo
call foofoo%add(1)
call foofoo%add(2.)
end program example

Я ожидаю, что это скомпилируется, и результаты должны быть 4 и 11. Однако gfortran сообщает о следующей ошибке:

procedure, public :: add => add_them
         1
Error: 'add_them' must be a module procedure or an external procedure with an explicit interface at (1)

Обходной путь — использовать процедуру с привязкой к типу generic вместо процедуры interfaced, чтобы модуль выглядел следующим образом:

module example_module
implicit none
private

type, public :: foo
  integer, private :: a=1,b=2
  real, private :: c=4.,d=5.
contains
  generic, public :: add => add_them_integer,add_them_real
  procedure, private :: add_them_integer,add_them_real
end type foo

contains
subroutine add_them_integer(self,x)
class(foo), intent(in) :: self
integer, intent(in) :: x
print *,self%a+self%b+x
end subroutine add_them_integer

subroutine add_them_real(self,x)
class(foo), intent(in) :: self
real, intent(in) :: x
print *,self%c+self%d+x
end subroutine add_them_real
end module example_module

Это работает, как и ожидалось. Однако я не могу использовать процедуру generic. Вышеприведенный пример является просто упрощенным примером для демонстрации проблемы, но в моем реальном коде add_them не может быть процедурой generic, потому что foo на самом деле является производным типом, а add_them переопределяет процедуру, определенную в родительском типе; gfortran (по крайней мере) не позволяет generic процедурам переопределять базовые процедуры. Чтобы обойти это ограничение, я подумал, что вместо этого должен использовать interface, но, как вы можете видеть в приведенном выше примере, хотя 'add_them' определен правильно, компилятор жалуется, что "'add_them' должен быть процедурой модуля или внешней процедурой с явный интерфейс».

Любая помощь будет оценена по достоинству; заранее спасибо.


person Pap    schedule 07.12.2013    source источник


Ответы (1)


Ошибка gfortran для вашего первого раздела кода верна. Способ выполнения общих привязок соответствует вашему разделу кода «работает как положено».

Если родительский тип имеет определенную привязку с определенным именем, вы не можете повторно использовать это имя в расширениях, кроме как для переопределения конкретной привязки.

Если вы хотите, чтобы add (обратите внимание, что имя add_them не появляется во втором случае) было универсальной привязкой в ​​расширениях, сделайте ее универсальной привязкой в ​​родительском элементе.

person IanH    schedule 07.12.2013
comment
Строго говоря, то, что я пытался сделать, это обойти ограничение, согласно которому вы не можете переопределить неуниверсальные процедуры универсальными, и попытался использовать для этой цели интерфейсную процедуру. Я закончил тем, что сделал, как сказал IanH, сделав родительскую процедуру общей. Это также требовало добавления конструкции select type в родительскую процедуру (чего я и хотел избежать), но это работает. - person Pap; 07.12.2013
comment
Однако я до сих пор не понимаю, почему процедура с интерфейсом не может быть процедурой с привязкой к типу, что делает процедуры generic единственным решением в приведенном выше примере. Fortran 2003/2008 даже позволяет переопределять имена типов с помощью интерфейсной процедуры, по сути создавая конструктор. Почему бы не использовать их и как процедуры с привязкой к типу? - person Pap; 07.12.2013
comment
То, что вы называете интерфейсной процедурой, является общим интерфейсом. Эквивалентом привязки является универсальная привязка. Процедуры, которые реализуют привязки, имеют требования к ним в отношении передаваемых аргументов и т. д. Если вы собираетесь использовать синтаксис автономного универсального интерфейса для указания общих привязок, тогда эти ограничения должны работать через этот синтаксис. Это было бы довольно грязно. - person IanH; 07.12.2013
comment
Я подозревал, что generic type-bounds — единственный путь, и опубликовал это, чтобы быть уверенным. Я не могу жаловаться, правда. В конце концов, именно эти ограничения делают Fortran идеальным для высокопроизводительных вычислений и заставляют программиста писать структурированный код, избегая потенциальных ловушек. - person Pap; 07.12.2013