指向纯函数 [英] Pointers in pure functions

查看:139
本文介绍了指向纯函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了遍历Fortran中的链表,我使用一个指向当前元素的指针,该指针移动到循环中的下一个元素。试图在> pure 函数中应用这个函数,该函数在所述链表上运行会导致错误。

示例:

 模块列表
隐式无

!节点
类型n_list
整数:: val
类型(n_list),pointer :: next => NULL()
结束类型

!链接列表
类型t_list
类型(n_list),指针::头部
结束类型

包含

纯函数in_list(list, val)result(res)
implicit none
class(t_list),intent(in):: list
整数,intent(in):: val
logical :: res
类型(n_list),指针:: cur

res = .true。
!遍历列表
cur =>如果(cur%val == val)返回
cur =>列表%head
while(associated(cur))
do cur%next
enddo

!未找到
res = .false。
结束功能
结束模块

结果

  cur => (1)


$ b中的PURE过程中的指针赋值中的目标不正确$ b

我知道错误/警告背后的基本原理,并且很难确保函数的参数在使用指针时不会发生变化(Fortran 2008,第12.7节纯粹的过程,尤其是 C1283)。但在这种情况下, list 永远不会改变。

是否可以告诉编译器( ifort gfortran intent(in)没有违反?

解决方案

好的,我找到了一个使用传输内部函数的解决方案。主要思想是克隆列表结构(没有数据,我检查过),并使用指向第一个节点的指针(不变)作为起始值。是的,这是一个循环漏洞,但是 ifort gfortran 在没有警告的情况下接受它。

 模块list_mod 
隐式无

!节点
类型n_list
整数:: val
类型(n_list),pointer :: next => NULL()
结束类型

!链接列表
类型t_list
类型(n_list),指针::头部
结束类型

包含

纯函数getHead(list)结果(res)
隐式无
类(t_list),意图(in)::列表
类型(n_list),指针:: res
类型(t_list),指针: :listPtr

!创建指向列表的指针的副本struct
allocate(listPtr)
listPtr = transfer(list,listPtr)

!设置指针
res => listPtr%head

!空闲内存
deallocate(listPtr)
结束函数

纯函数in_list(list,val)结果(res)
隐式无
class(t_list) ,intent(in):: list
integer,intent(in):: val
logical :: res
type(n_list),pointer :: cur

res = .true。

!遍历列表
cur => getHead(list)
while(associated(cur))
if(cur%val == val)return
cur => cur%next
enddo

!未找到
res = .false。
结束函数

结束模块

程序测试
使用list_mod
隐式无
整数,参数:: MAXELEM = 10000000
integer :: i
type(t_list):: list
type(n_list),pointer :: cur

!填写清单
清单%head => NULL()
allocate(list%head)
list%head%val = 1

cur => list%head
do i = 2,MAXELEM
allocate(cur%next)
cur%next%val = i
cur => cur%next
enddo!i

print *,'是列表中的MAXELEM / 2吗? ',in_list(list,MAXELEM / 2)
print *,'是列表中的MAXELEM + 1? ',in_list(list,MAXELEM + 1)
end program


In order to traverse a linked list in Fortran, I use a pointer to the current element that is moved to the next one inside a loop. Trying to apply this inside a pure function that operates on said linked list results in an error.

Example:

module list
  implicit none

  ! Node
  type n_list
    integer               :: val
    type(n_list),pointer  :: next => NULL()
  end type

  ! Linked list
  type t_list
    type(n_list),pointer  :: head
  end type

contains

  pure function in_list( list, val ) result(res)
    implicit none
    class(t_list),intent(in)  :: list
    integer,intent(in)        :: val
    logical                   :: res
    type(n_list),pointer      :: cur

    res = .true.
    ! Traverse the list
    cur => list%head
    do while ( associated(cur) )
      if ( cur%val == val ) return 
      cur => cur%next
    enddo

    ! Not found
    res = .false.
  end function
end module

Results in

    cur => list%head
         1
Error: Bad target in pointer assignment in PURE procedure at (1)

I am aware of the rationale behind the error/warning, and that it is difficult to ensure that the arguments of the function are not changed when using pointers (Fortran 2008, ch. 12.7 "Pure procedures", esp. C1283). In this case, though, list is never changed.

Is it possible to tell the compiler (ifort and gfortran) that intent(in) is not violated?

解决方案

OK, I found a solution using the transfer intrinsic. The main idea is to clone the list struct (without the data, I checked), and use the pointer to the first node (unchanged) as a start value. Yeah, it is a loop-hole, but both ifort and gfortran accept this without warnings.

module list_mod
  implicit none

  ! Node
  type n_list
    integer               :: val
    type(n_list),pointer  :: next => NULL()
  end type

  ! Linked list
  type t_list
    type(n_list),pointer  :: head
  end type

contains

  pure function getHead(list) result(res)
    implicit none
    class(t_list),intent(in)  :: list
    type(n_list),pointer      :: res
    type(t_list),pointer      :: listPtr

    ! Create a copy of pointer to the list struct
    allocate( listPtr )
    listPtr = transfer( list, listPtr )

    ! Set the pointer
    res => listPtr%head

    ! Free memory
    deallocate( listPtr )
  end function

  pure function in_list( list, val ) result(res)
    implicit none
    class(t_list),intent(in)  :: list
    integer,intent(in)        :: val
    logical                   :: res
    type(n_list),pointer      :: cur

    res = .true.

    ! Traverse the list
    cur => getHead(list)
    do while ( associated(cur) )
      if ( cur%val == val ) return
      cur => cur%next
    enddo

    ! Not found
    res = .false.
  end function

end module

program test
  use list_mod
  implicit none
  integer,parameter     :: MAXELEM = 10000000
  integer               :: i
  type(t_list)          :: list
  type(n_list),pointer  :: cur

  ! Fill list
  list%head => NULL()
  allocate( list%head )
  list%head%val = 1

  cur => list%head
  do i=2,MAXELEM
    allocate( cur%next )
    cur%next%val = i
    cur => cur%next
  enddo !i

  print *,'is MAXELEM/2 in list? ', in_list( list, MAXELEM/2 )
  print *,'is MAXELEM+1 in list? ', in_list( list, MAXELEM+1 )
end program

这篇关于指向纯函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆