Конфликт между определенным назначением и внутренним назначением (с помощью nagfor)?
Внутреннее полиморфное присвоение является недавней особенностью некоторых компиляторов Фортрана (например, ifort 18, nagfor 6.2), которая недоступна в более старых версиях (например, ifort 17, gfortran 6.3). Хорошо известное решение, которое работает с этими более старыми версиями, состоит в том, чтобы использовать определенное назначение, как в примере ниже (взято и адаптировано из книги Чиверса и Слайтхолма):
module deftypes
type, abstract :: shape_t
integer :: x = 0, y = 0
end type shape_t
type, extends(shape_t) :: circle_t
integer :: radius = 0
end type circle_t
interface assignment(=)
module procedure generic_shape_assign
end interface
contains
subroutine generic_shape_assign ( lhs, rhs )
class(shape_t), intent(in ) :: rhs
class(shape_t), allocatable, intent(out) :: lhs
print*,' --> in generic_shape_assign'
allocate(lhs, source = rhs)
end subroutine generic_shape_assign
end module deftypes
program check_assign
use deftypes
implicit none
class(shape_t), allocatable :: myshape
type (circle_t) :: mycirc1, mycirc2
mycirc1 = circle_t ( 1, 2, 3 )
print*,'A polymorphic assignment: myshape = mycirc1'
myshape = mycirc1
print*,'An intrinsic assignment: mycirc2 = mycirc1'
mycirc2 = mycirc1
end program check_assign
Этот пример компилируется и хорошо работает с ifort 15.0.3 и gfortran 6.3.0. Но с nagfor 6.2 я получаю следующую ошибку во время компиляции (для строки mycirc2=mycirc1
):
Error: check_assign.f90, line 41: Incorrect data type CIRCLE_T (expected SHAPE_T) for argument LHS (no. 1) of GENERIC_SHAPE_ASSIGN
Мне не понятно, почему этот компилятор пытается использовать определенное присваивание в инструкции mycirc2 = mycirc1
в то время как эти две переменные не являются выделяемыми полиморфными.
Конечно, если я удалю определенное назначение, оно будет работать с nagfor, но не с другими старыми компиляторами. Есть идеи, откуда появилась эта ошибка и как ее обойти?
1 ответ
Я считаю, что компилятор правильно отклонить эту программу. Однако, если у вас есть контракт на поддержку с NAG, я настоятельно рекомендую попросить их принять мои комментарии как окончательные.
Я покажу свои рассуждения.
Понятно, что ссылка на конкретную процедуру generic_shape_assign
лайк
type(circle_t) mycirc1, mycirc2
call generic_shape_assign(mycirc2, mycirc1)
не является действительным. Это не удается, потому что фактический аргумент mycirc2
соответствует выделенному полиморфному фиктивному аргументу lhs
:
- не подлежит распределению;
- не имеет того же объявленного типа, что и соответствующий фиктивный аргумент;
- не полиморфный.
В сообщении об ошибке, которое вы цитируете, говорится об отказе программы за нарушение этой секунды.
Итак, это означает, что generic_shape_assign
не является допустимой конкретной процедурой (для этой ссылки) с общей спецификацией assignment(=)
, право? И, таким образом, не определено присвоение, и компилятор должен вернуться к внутреннему присваиванию?
Здесь вещи становятся мутными (по крайней мере, для меня).
Я думаю, что конкретная подпрограмма generic_shape_assign
выбран для определенного назначения, и поэтому компилятор корректен, чтобы отклонить вашу программу, потому что вы не вызываете эту конкретную подпрограмму правильно.
Давайте посмотрим дальше, используя Fortran 2008 7.2.1.4, где есть определение того, когда оператор присваивания является определенным оператором присваивания.
Чтобы решить, будет ли подпрограмма generic_shape_assign
определяет определенный оператор присваивания mycirc2=mycirc1
мы смотрим на данные моменты:
generic_shape_assign
это подпрограмма с двумя фиктивными аргументами (lhs
а такжеrhs
Вот);- блок интерфейса дает
generic_shape_assign
общая спецификацияassignment(=)
; lhs
(типаshape_t
) совместим с типомmycirc2
(динамического типаcircle_t
);rhs
так же;- нет параметров типа для фиктивных или фактических аргументов;
- ранги (будучи скалярными) фиктивных и фактических аргументов совпадают.
Мы выполняем все требования для этого, являющегося определенным назначением: не существует требования, в котором говорится, что определенное назначение требует, чтобы выбранная подпрограмма вызывалась!
В итоге:
Мне не понятно, почему этот компилятор пытается использовать определенное присваивание в инструкции
mycirc2 = mycirc1
в то время как эти две переменные не являются выделяемыми полиморфными.
Потому что то, используется ли определенное присваивание, не связано с тем, являются ли левая и правая части полиморфными или выделяемыми.
Наконец, я думаю, что диагностическое сообщение от компилятора может быть улучшено независимо от того, правильны ли мои рассуждения или нет.