Неограниченный полиморфный фиктивный аргумент с размещаемыми или указательными атрибутами? - PullRequest
2 голосов
/ 05 июня 2019

В проекте, над которым я работаю, мне часто приходится изменять размеры массивов объектов по мере создания новых объектов и уничтожения старых.Это происходит с многочисленными различными производными типами в коде, большинство из которых не имеют отношения друг к другу.Написание кода для изменения размера этих массивов для уникального производного типа утомительно, поэтому я подумал, что попробую написать пару подпрограмм-помощников, использующих неограниченные полиморфные фиктивные аргументы, чтобы любой массив производного типа мог использовать эти подпрограммы.

ЧтоЯ обнаружил, что моя неограниченная полиморфная процедура может быть скомпилирована и вызвана с помощью CLASS(*),INTENT(INOUT) :: val.Этот фиктивный аргумент будет принимать целое число, выделяемое целое число или указатель на целое число.Однако, как только я пытаюсь добавить атрибуты ALLOCATABLE или POINTER, подпрограмма компилируется правильно, но я не могу вызвать ее, не получив ошибку компилятора.Поскольку моя цель состоит в том, чтобы иметь возможность изменять размеры массивов производных типов, эти атрибуты необходимы для того, чтобы подпрограмма могла освобождать / распределять / ассоциировать значения.

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

MODULE Resize_mod
PUBLIC
CONTAINS
  SUBROUTINE resize(val)
    CLASS(*),INTENT(INOUT) :: val
    WRITE(*,*) 'resize'
  ENDSUBROUTINE resize
  SUBROUTINE resize_alloc(val)
    CLASS(*),ALLOCATABLE,INTENT(INOUT) :: val
    WRITE(*,*) 'resize_alloc'
  ENDSUBROUTINE resize_alloc
  SUBROUTINE resize_ptr(val)
    CLASS(*),POINTER,INTENT(INOUT) :: val
    WRITE(*,*) 'resize_ptr'
  ENDSUBROUTINE resize_ptr
ENDMODULE Resize_mod

PROGRAM testResize
  USE Resize_mod
  INTEGER,TARGET :: array0d
  INTEGER,ALLOCATABLE :: alloc0d
  INTEGER,POINTER :: ptr0d

  array0d=1
  CALL resize(array0d)

  ALLOCATE(alloc0d)
  alloc0d=1
  CALL resize(alloc0d)
  !Following line gives: "Error: Actual argument to ‘val’ at (1) must be polymorphic"
  CALL resize_alloc(alloc0d)

  ALLOCATE(ptr0d)
  ptr0d=1
  CALL resize(ptr0d)
  !Following line gives: "Error: Actual argument to ‘val’ at (1) must be polymorphic"
  CALL resize_ptr(ptr0d)

ENDPROGRAM testResize

Как показано, код выдает следующие ошибки:

testResize.f90:31:20:

   CALL resize_alloc(alloc0d)
                    1
Error: Actual argument to ‘val’ at (1) must be polymorphic
testResize.f90:37:18:

   CALL resize_ptr(ptr0d)
                  1
Error: Actual argument to ‘val’ at (1) must be polymorphic

Если я закомментирую 2 строки, названные в ошибках, я получу следующий правильный вывод:

 resize
 resize
 resize

Я много писал код на Фортране, но никогда раньше не пытался использовать неограниченный полиморфизм.Пожалуйста, дайте мне знать, возможно ли то, что я пытаюсь сделать, и если да, то, что я делаю неправильно.

Я использую компилятор gfortran 5.4.0, который должен полностью поддерживать неограниченный полиморфизм, насколько это возможно.Я могу сказать.

Ответы [ 2 ]

2 голосов
/ 06 июня 2019

Сообщение об ошибке является лишь повторением ограничения в правилах языка - см. 15.5.2.5p2 в стандарте Fortran 2018. Существует ограничение, позволяющее запретить вызываемой процедуре перераспределять размещаемый фиктивный аргумент в другой тип или тип из фактического аргумента (или, для фиктивных аргументов-указателей, связать фиктивный объект с другим типом или видом). Это не относится к неограниченным полиморфным аргументам - оно применяется к любому выделяемому или полиморфному фиктивному аргументу-указателю, и в этом случае ограничение в языке не позволяет процедуре выделить фиктивный аргумент для другой ветви дерева наследования типов.

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

Язык обеспечивает некоторую поддержку синтаксиса для общих операций над массивами в общем виде, однако они не могут быть эффективно реализованы современными компиляторами. Например, элемент может быть добавлен в размещаемый массив с синтаксисом array = [ array, element ].

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

Улучшенная поддержка универсального программирования - это аспект, который рассматривается в следующей редакции языка.

1 голос
/ 05 июня 2019

Когда у вас есть размещаемый объект, объявленный как

class(*), allocatable :: obj(:)

, для фиктивного аргумента невозможно указать, что природа «выделяемого» применяется независимо к форме массива или аспектам типа.

Как только вы говорите, что фиктивный аргумент имеет атрибут allocatable, к фиктивному аргументу и соответствующему фактическому аргументу применяются все ограничения.В этом случае выделяемый неограниченный полиморфный фиктивный аргумент может быть связан только с размещаемым неограниченным полиморфным фактическим аргументом. 1

Фактический аргумент alloc0d имеет объявленный тип integer и являетсяне безграничный полиморфный.Поэтому такая ссылка на процедуру недопустима.

Та же логика явно применяется для указателя-пустышки / фактического аргумента.Для полноты, если фиктивная переменная не является неограниченной полиморфной, то для фактического аргумента необходимо, чтобы он был того же объявленного типа.

Без атрибута allocatable или pointer для аргументов фиктивного аргументаассоциации действительны.

Чтобы иметь возможность изменить аргумент фиктивного массива с размещаемым указателем / указателем, необходимо, чтобы фиктивный аргумент не был полиморфным.Вам нужно будет найти другой способ обработки таких случаев (возможно, с помощью дженериков).


1 Мотивация для этого заключается в том, что внутри процедуры у выделяемого полиморфного фиктивного аргумента может быть свойдинамический тип, а также его форма (если это массив) изменились в операторе allocate.Это утверждение явно не может повлиять на связанный фактический аргумент, если он не определен совместимым образом.Это снова относится к правилам Фортрана: мы не можем сказать «этот объект полиморфный, но я обещаю не менять его тип».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...