объявление класса fortran фиктивного аргумента

Я хотел бы иметь производный тип a, который пуст. Из этого производного типа я хотел бы определить дополнительные типы, расширяющие a. Предположим, что все эти расширения типа содержат некоторое имя процедуры generic, value, т.е. value => valuea1, value => valuea2 и т. д.

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

Предположительно, я мог бы обойти это, используя некоторую процедуру с именем value внутри определения типа a (затем переопределяя в расширениях). Однако, учитывая, что я никогда не хочу объявлять какой-либо объект с типом a, это выглядит беспорядочно. Можно ли обойти это?


person Ted Burgess    schedule 11.03.2014    source источник


Ответы (2)


Да, вы можете объявить связанную с типом процедуру даже для типа abstract. Это может быть процедура с привязкой к реальному типу или просто abstract interface.

type, abstract :: a
contains
  procedure :: valuea1, valuea2
  generic value :: value => valuea1, valuea2
end type


abstract interface
  ! the headers of valuea1, valuea2 here
  ! they should have a passed dummy argument class(a)
  ! and some other argument for the generic resolution
  ! for example:

  subroutine valua1(self, x)
    class(a), intent(in) :: self
    real, intent(inout) :: x
  end subroutine

  subroutine valua2(self, x)
    class(a), intent(in) :: self
    integer, intent(inout) :: x
  end subroutine

end interface

Таким образом, вы не можете создавать переменные type(a), но можете создавать расширенные типы, которые реализуют свои собственные версии value.

person Vladimir F    schedule 11.03.2014
comment
Спасибо за Ваш ответ. Я не уверен, что полностью следую... Мне на самом деле не нужно общее разрешение; valuea1 и valuea2 принимают один и тот же тип аргументов для проблемы, которую я имею в виду, я просто хочу привязаться к valuea1 в одном расширении типа и valuea2 в другом расширении типа. Уместен ли здесь атрибут deferred? - person Ted Burgess; 12.03.2014
comment
Затем вы просто привязываете value к различным процедурам в расширенных типах. Но тогда их интерфейсы должны быть согласованы. - person Vladimir F; 12.03.2014

Аналогично ответу @VladimirF, но с учетом вашего разъяснения, что

На самом деле мне не нужно общее разрешение; valuea1 и valuea2 принимают один и тот же тип аргументов для проблемы, которую я имею в виду, я просто хочу привязаться к valuea1 в одном расширении типа и valuea2 в другом расширении типа.

Таким образом, здесь базовый (абстрактный) тип определяет отложенную процедуру с привязкой к типу value() с интерфейсом, принимающим class(a) в качестве передаваемого аргумента. Можно добавить другие аргументы. Каждый расширяющий тип определяет/переопределяет эту связанную с типом процедуру своей собственной процедурой.

Это означает, что в нашем последнем вызове подпрограммы test_sub фиктивный аргумент class(a) имеет %value().

module types

! The base type
  type, abstract :: a
   contains
     procedure(value_if), deferred :: value
  end type a

! The interface for the type-bound procedures
  abstract interface
     subroutine value_if(var)
       import a
       class(a) var
     end subroutine value_if
  end interface

! The extending types, overriding the value subroutine

  type, extends(a) :: a1
   contains
     procedure :: value => value_a1
  end type a1

  type, extends(a) :: a2
   contains
     procedure :: value => value_a2
  end type a2

contains

  subroutine value_a1(var)
    class(a1) var
    print*, "Value of a1"
  end subroutine value_a1

  subroutine value_a2(var)
    class(a2) var
    print*, "Value of a2"
  end subroutine value_a2

end module types


program test

  use types

  type(a1) x
  type(a2) y

  call x%value
  call y%value

  call test_sub(x)
  call test_sub(y)

contains

  subroutine test_sub(var)
    class(a) var
    call var%value  ! This is defined
  end subroutine test_sub

end program test

Это производит вывод

Значение a1
Значение a2
Значение a1
Значение a2

person francescalus    schedule 11.03.2014
comment
Спасибо за ответ. Итак, если я хочу, чтобы value_a1 и value_a2 имели разное количество фиктивных аргументов, нужно ли мне перегружать абстрактный интерфейс? Извините за мое невежество... Как вы можете заметить, я все еще нахожусь на ранней стадии изучения современного фортрана. - person Ted Burgess; 12.03.2014
comment
То, что я хотел бы сделать, это что-то вроде того, что предложил Владимир Ф, но где общее разрешение выполняется в соответствии с классом self, а не с фиктивным аргументом x. Хотя кажется, что это невозможно. - person Ted Burgess; 12.03.2014
comment
Вот что здесь происходит: если у вас type(a1) self, то self%value() разрешается в a1_value(self). [Честно говоря, я не заметил часть про x различных типов.] - person francescalus; 12.03.2014
comment
Таким образом, проблема заключается в необходимости согласованных интерфейсов. Кажется, у меня может быть некоторая процедура с именем value, которая ничего не делает (и никогда не будет вызываться, потому что я не буду объявлять переменные типа a), а затем привязывать значение в расширениях. Я просто надеялся, что будет какой-то другой способ, но потому что избыточная процедура кажется очень неэлегантной! Хотя, возможно, при переопределении значения в расширениях я все равно столкнусь с проблемами из-за несогласованности интерфейса? - person Ted Burgess; 12.03.2014
comment
Пока игнорируем привязку типов и говорим, что у вас есть type(a1) x и type(a2) y. Преимущество отложенной привязки типа value состоит в том, что для class(a) z можно выполнить call value(z). Если вместо этого вы хотите выбирать (динамически) между call value(x, p) и call value(y, p, q) для универсального value, то это преимущество исчезнет, ​​так как вам уже придется ограничивать class(a). [Хотя см. stackoverflow.com/a/21487114/3157076.] - person francescalus; 12.03.2014
comment
И, с практической точки зрения, не существует процедуры, которая ничего не делает: то, что можно было бы назвать a%value, не существует точно так же, как никогда не бывает объекта type(a). - person francescalus; 12.03.2014