存储“指向函数的指针”。在 Fortran 语言中?

发布于 2024-09-26 20:13:31 字数 469 浏览 2 评论 0原文

在 Fortran 中,您可以将函数/子例程 A 作为参数传递给另一个函数/子例程 B,但是您可以存储 A 以供以后检索和使用吗?

例如,这在 C 中是允许的。

int foo(float, char, char) { /*whatever*/};

int (*pointerToFunction)(float, char, char);
pointerToFunction = foo;

在 Fortran 中,您可以将子例程作为参数传递

subroutine foo
! whatever
end subroutine foo

subroutine bar(func)
    call func
end subroutine bar

program x

    call bar(foo)

end program

,但是如何以与 C 类似的方式存储 foo 的地址?

In Fortran, you can pass a function/subroutine A as an argument to another function/subroutine B, but can you store A for later retrieval and use?

for example, this is allowed in C

int foo(float, char, char) { /*whatever*/};

int (*pointerToFunction)(float, char, char);
pointerToFunction = foo;

In Fortran you can pass a subroutine as an argument

subroutine foo
! whatever
end subroutine foo

subroutine bar(func)
    call func
end subroutine bar

program x

    call bar(foo)

end program

but how can you store the address of foo in a similar way to C ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

旧夏天 2024-10-03 20:13:31

从所谓的“Fortran 2003”(ISO/IEC 1539-2004)开始,过程指针是 Fortran 语言的一部分。这绝对是 Fortran 语言的主要新特性之一。

用法来自 Fortran Wiki 的 示例


Stefano,你提到了策略设计模式。在Fortran 2003中您可以使用纯OOP方式来实现它(无需过程指针)。临时示例:

strategies.f90

module strategies

  implicit none

  private

  public :: strategies_transportation_strategy, &
            strategies_by_taxi_strategy, &
            strategies_by_bus_strategy

  type, abstract :: strategies_transportation_strategy
  contains
    procedure(transportation_strategy_go), deferred :: go
  end type strategies_transportation_strategy

  type, extends(strategies_transportation_strategy) :: strategies_by_taxi_strategy
  contains
    procedure :: go => strategies_by_taxi_strategy_go
  end type strategies_by_taxi_strategy

  type, extends(strategies_transportation_strategy) :: strategies_by_bus_strategy
  contains
    procedure :: go => strategies_by_bus_strategy_go
  end type strategies_by_bus_strategy

  abstract interface
    subroutine transportation_strategy_go(this)
      import strategies_transportation_strategy
      class(strategies_transportation_strategy), intent(in) :: this
    end subroutine transportation_strategy_go
  end interface

  contains

    subroutine strategies_by_taxi_strategy_go(this)
      class(strategies_by_taxi_strategy), intent(in) :: this

      print *, "We are using taxi."

    end subroutine strategies_by_taxi_strategy_go

    subroutine strategies_by_bus_strategy_go(this)
      class(strategies_by_bus_strategy), intent(in) :: this

      print *, "We are using public transport."

    end subroutine strategies_by_bus_strategy_go

end module strategies

cars.f90

module vehicles

  use strategies

  implicit none

  private

  public :: vehicles_vehicle, &
            vehicles_taxi, &
            vehicles_bus

  type, abstract :: vehicles_vehicle
    private
    class(strategies_transportation_strategy), allocatable :: transportation_strategy
  contains
    procedure :: set_transportation_strategy => vehicle_set_transportation_strategy
    procedure :: go => vehicle_go
  end type vehicles_vehicle

  type, extends(vehicles_vehicle) :: vehicles_taxi
  contains
    procedure :: init => taxi_init
  end type vehicles_taxi

  type, extends(vehicles_vehicle) :: vehicles_bus
  contains
    procedure :: init => bus_init
  end type vehicles_bus

  contains

    subroutine vehicle_go(this)
      class(vehicles_vehicle), intent(in) :: this

      call this%transportation_strategy%go()

    end subroutine vehicle_go

    subroutine vehicle_set_transportation_strategy(this, new_transportation_strategy)
      class(vehicles_vehicle), intent(inout) :: this
      class(strategies_transportation_strategy), intent(in) :: new_transportation_strategy

      if (allocated(this%transportation_strategy)) then
        deallocate (this%transportation_strategy)
      end if

      allocate (this%transportation_strategy, source=new_transportation_strategy)

    end subroutine vehicle_set_transportation_strategy

    subroutine taxi_init(this)
      class(vehicles_taxi), intent(out) :: this

      type(strategies_by_taxi_strategy) :: by_taxi_strategy

      call this%set_transportation_strategy(by_taxi_strategy)

    end subroutine taxi_init

    subroutine bus_init(this)
      class(vehicles_bus), intent(out) :: this

      type(strategies_by_bus_strategy) :: by_bus_strategy

      call this%set_transportation_strategy(by_bus_strategy)

    end subroutine bus_init

end module vehicles

main.f90

program main

  use vehicles

  implicit none

  type(vehicles_taxi) :: taxi
  type(vehicles_bus) :: bus

  call taxi%init()
  call bus%init()

  call taxi%go()
  call bus%go()

end program main

至少可以使用 gfortran 4.6 (20100925)。

Starting from so-called "Fortran 2003" (ISO/IEC 1539-2004) procedure pointers is a part of the Fortran language. It's definitely of the major new features of Fortran language.

Usage example from Fortran Wiki.


Stefano, you mentioned strategy design pattern. In Fortran 2003 you can use pure OOP way to implement it (without procedure pointers). Offhand example:

strategies.f90

module strategies

  implicit none

  private

  public :: strategies_transportation_strategy, &
            strategies_by_taxi_strategy, &
            strategies_by_bus_strategy

  type, abstract :: strategies_transportation_strategy
  contains
    procedure(transportation_strategy_go), deferred :: go
  end type strategies_transportation_strategy

  type, extends(strategies_transportation_strategy) :: strategies_by_taxi_strategy
  contains
    procedure :: go => strategies_by_taxi_strategy_go
  end type strategies_by_taxi_strategy

  type, extends(strategies_transportation_strategy) :: strategies_by_bus_strategy
  contains
    procedure :: go => strategies_by_bus_strategy_go
  end type strategies_by_bus_strategy

  abstract interface
    subroutine transportation_strategy_go(this)
      import strategies_transportation_strategy
      class(strategies_transportation_strategy), intent(in) :: this
    end subroutine transportation_strategy_go
  end interface

  contains

    subroutine strategies_by_taxi_strategy_go(this)
      class(strategies_by_taxi_strategy), intent(in) :: this

      print *, "We are using taxi."

    end subroutine strategies_by_taxi_strategy_go

    subroutine strategies_by_bus_strategy_go(this)
      class(strategies_by_bus_strategy), intent(in) :: this

      print *, "We are using public transport."

    end subroutine strategies_by_bus_strategy_go

end module strategies

vehicles.f90

module vehicles

  use strategies

  implicit none

  private

  public :: vehicles_vehicle, &
            vehicles_taxi, &
            vehicles_bus

  type, abstract :: vehicles_vehicle
    private
    class(strategies_transportation_strategy), allocatable :: transportation_strategy
  contains
    procedure :: set_transportation_strategy => vehicle_set_transportation_strategy
    procedure :: go => vehicle_go
  end type vehicles_vehicle

  type, extends(vehicles_vehicle) :: vehicles_taxi
  contains
    procedure :: init => taxi_init
  end type vehicles_taxi

  type, extends(vehicles_vehicle) :: vehicles_bus
  contains
    procedure :: init => bus_init
  end type vehicles_bus

  contains

    subroutine vehicle_go(this)
      class(vehicles_vehicle), intent(in) :: this

      call this%transportation_strategy%go()

    end subroutine vehicle_go

    subroutine vehicle_set_transportation_strategy(this, new_transportation_strategy)
      class(vehicles_vehicle), intent(inout) :: this
      class(strategies_transportation_strategy), intent(in) :: new_transportation_strategy

      if (allocated(this%transportation_strategy)) then
        deallocate (this%transportation_strategy)
      end if

      allocate (this%transportation_strategy, source=new_transportation_strategy)

    end subroutine vehicle_set_transportation_strategy

    subroutine taxi_init(this)
      class(vehicles_taxi), intent(out) :: this

      type(strategies_by_taxi_strategy) :: by_taxi_strategy

      call this%set_transportation_strategy(by_taxi_strategy)

    end subroutine taxi_init

    subroutine bus_init(this)
      class(vehicles_bus), intent(out) :: this

      type(strategies_by_bus_strategy) :: by_bus_strategy

      call this%set_transportation_strategy(by_bus_strategy)

    end subroutine bus_init

end module vehicles

main.f90

program main

  use vehicles

  implicit none

  type(vehicles_taxi) :: taxi
  type(vehicles_bus) :: bus

  call taxi%init()
  call bus%init()

  call taxi%go()
  call bus%go()

end program main

At least works using gfortran 4.6 (20100925).

计㈡愣 2024-10-03 20:13:31

以下代码演示了如何使用过程指针:

module my_mod
  implicit none
contains
  subroutine sub1()
    write(*,*) 'the first suboutine is being used'
  end subroutine sub1

  subroutine sub2()
    write(*,*) 'the second subroutine is being used'
  end subroutine sub2

end module my_mod

program procTest
  use my_mod
  implicit none                                             
  integer :: n
  procedure(sub1), pointer:: funPointer => NULL()
  write(*,'(A)') "Please enter your option"
  read(*,*) n                                                                  
  select case( n )
  case( 1 )
     funPointer => sub1
  case( 2 )
     funPointer => sub2
  case DEFAULT
     funPointer => sub1
  end select
  call funPointer()
end program procTest

The following codes demonstrate how to use procedure pointers:

module my_mod
  implicit none
contains
  subroutine sub1()
    write(*,*) 'the first suboutine is being used'
  end subroutine sub1

  subroutine sub2()
    write(*,*) 'the second subroutine is being used'
  end subroutine sub2

end module my_mod

program procTest
  use my_mod
  implicit none                                             
  integer :: n
  procedure(sub1), pointer:: funPointer => NULL()
  write(*,'(A)') "Please enter your option"
  read(*,*) n                                                                  
  select case( n )
  case( 1 )
     funPointer => sub1
  case( 2 )
     funPointer => sub2
  case DEFAULT
     funPointer => sub1
  end select
  call funPointer()
end program procTest
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文