Проблема типа указателя gfortran - PullRequest
0 голосов
/ 16 мая 2018

Я пытаюсь создать процедуру, которая может принимать разные типы ввода без использования общей процедуры.Действительно (в данном случае) я предпочитаю вручную устанавливать цель указателя процедуры, чтобы определить, какую процедуру использовать, а не общую процедуру.

Это то, что я делаю со следующим почти минимальным примером.

module mo
implicit none

type :: TypeB
    character(len=5) :: info='Hello'
    contains
    procedure,  pass(fd) :: say_hello 
end type TypeB

type :: TypeA
    character(len=4) :: txt='Hola'
    !type(TypeB) :: Tb
end type TypeA

type, extends(TypeA) :: TypeC
    character(len=4) :: tt='Hey!'
    type(TypeB) :: Tb
end type TypeC

type, extends(TypeA) :: TypeD
    character(len=3) :: tt='Ho!'
    character(len=3) :: ti='you'
    !type(TypeB) :: Tb
end type TypeD

type(TypeC) :: Tc
type(TypeD) :: Td
procedure(), pointer :: proc
class(TypeA), allocatable :: CA


contains

subroutine say_hello(fd)
    implicit none
    ! type(TypeB), intent(inout) :: fd
    class(TypeB), intent(inout) :: fd

    print *, fd%info

end subroutine say_hello

subroutine procC(fd, args)
    implicit none
    ! class(TypeC), intent(inout) :: fd
    type(TypeC), intent(inout) :: fd
    real :: args

    print*, args
    print*, fd%tt
    call fd%Tb%say_hello()
end subroutine procC

subroutine procD(fd, args)
    implicit none
    ! class(TypeD), intent(inout) :: fd
    type(TypeD), intent(inout) :: fd
    ! class(TypeA), intent(inout) :: fd
    real :: args

    print*, args
    print*, fd%tt
    print*, fd%ti
end subroutine procD

end module mo


program p
    use mo
    implicit none

    print* , 'START'
    print *, Tc%tb%info
    print *, Tc%txt
    call Tc%Tb%say_hello()
    call procC(Tc, 1.0)
    call procD(Td, 2.0)
    print*, 'OK'

    allocate(TypeD :: CA)
    proc =>procD
    call proc(CA, 3.0)
    deallocate(CA)

    allocate(TypeC :: CA)
    proc =>procC
    call proc(CA, 4.0)
    deallocate(CA)

    print*, 'END'

end program p

Я получаю ожидаемые результаты при компиляции с помощью ifort в Linux, но при компиляции с помощью gfortran (MinGW 6.2.0) в Windows или в Linux (gfortran 5.5.0 и 6.4.0) я получаю что-тостранно:

START
Hello
Hola
Hello
1.00000000
Hey!
Hello
2.00000000
Ho!
you
OK
3.00000000

@R
4.00000000

ÇR@
END

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

Итак, есть ли способ избежать этих проблем?Это ошибка Gfortran?Или я что-то неправильно понимаю?

1 Ответ

0 голосов
/ 16 мая 2018

Ваша программа здесь неисправна.

Рассмотрим раздел

proc =>procD
call proc(CA, 3.0)

, который я сначала рассмотрю как

call procD(CA,3.0)

Подпрограмма procD имеет первый фиктивный аргумент, объявленный как type(typeD). Это неполиморфная сущность динамического и объявленного типа typeD. Фактический аргумент CA основной программы - это полиморфная сущность динамического типа typeD, но объявленный тип typeA.

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

В рабочей версии

call procD(Td, 2.0)

фактический аргумент Td имеет объявленный тип typeD и поэтому совместим с типом.

Использование здесь указателя процедуры с неявным интерфейсом усложняет компилятору обнаружение этой ошибки в вашей программе (что не требуется делать).

...