使用可选参数重载函数

Overloading functions with optional arguments

我想编写一个带有 optional 参数的过程,该参数可以是 FooType 类型或 BarType 类型,这样该程序是有效的:

module m
  implicit none
  
  type :: FooType
  end type
  
  type :: BarType
  end type
end module

program mwe
  use m
  implicit none
  
  type(FooType), allocatable :: foo(:)
  type(BarType), allocatable :: bar(:)
  
  call func()
  call func([FooType()])
  call func([BarType()])
  call func(foo)
  call func(bar)
end program

我目前的尝试是:

module m
  implicit none
  
  type :: FooType
  end type
  
  type :: BarType
  end type
  
  interface func
    module procedure func_FooType
    module procedure func_BarType
  end interface
contains

subroutine func_FooType(input)
  type(FooType), intent(in), optional :: input(:)
  write(*,*) 'foo'
end subroutine

subroutine func_BarType(input)
  type(BarType), intent(in) :: input(:)
  write(*,*) 'bar'
end subroutine
end module

但这不起作用。使用 gfortran 10.1.0ifort 2021.1 编译给出输出

foo
foo
bar
foo
bar

问题是最后一次调用 func(bar)bar 不是 allocated,因此如果它被传递给 optional 参数,它就不会是 present。但是,被调用的过程是 func_BarType,它认为它的 input 不是 optional,因此无法检查 input 是否是 present。实际上,如果我将 input 更改为标量而不是数组,则在 gfortran 下对 func(bar) 的调用会在运行时崩溃。

我认为唯一的方法是使用一个带有可选多态参数的函数,所以:

subroutine func(input)
  class(*), intent(in), optional :: input(:)
  
  if (present(input)) then
    select type(input); type is(FooType)
      ! Code for FooType.
    type is(BarType)
      ! Code for BarType.
    class default
      ! Any other class. Probably throw an error.
    end select
  else
    ! Code for input not present.
  endif
end subroutine

令我惊讶的是,似乎没有不使用多态类型就可以做到这一点的方法。