在Fortran中有一个函数返回一个可以放在作业左侧的参考 [英] Have a function in fortran return a reference that can be placed on the left-hand-side of an assignment

查看:210
本文介绍了在Fortran中有一个函数返回一个可以放在作业左侧的参考的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

正如标题所述,我希望直接修改通过从函数检索的指针访问的数据。由l.h.s.中显示的函数返回引用。 (=)在C ++中是没有问题的,但是以下fortran错误中的最小示例为:

  module test_mod 
隐含无

整数,目标:: a = 1,b = 2,c = 3!一些成员变量

包含

函数get(i)
整数,pointer :: get
整数,intent(in):: i

select case(i)
case(1)
get =>
案例(2)
get => b
案例(3)
get => c
结束选择
结束函数获得

结束模块test_mod

程序测试
使用test_mod
隐式无
整数,指针:: i_p

!>打印出1 2 3
print *,get(1),get(2),get(3)

!>这是我想要的,但我得到错误
!>错误:(1)处的'get'不是变量
get(2)= 5

!>这工作,但不是我想要的
i_p => get(2)
i_p = 5

结束程序测试

有什么办法来完成这种行为;也许我错过了一些属性?我想绕过编写任何setter例程,比如

  set(i,value)

,因为它应该模仿数组的外观。
在我的应用程序中,成员变量 a,b,c 实际上是不同大小的数组


  a = [a1,a2,a3] 
b = [b1,b2]
c = [c1]

,我希望getter get(i,j)来模拟一个指针矩阵。 b
$ b

  j = 1 2 3 

i = 1:[[a1,a2,a3],
i = 2 :[b1,b2,XX],
i = 3:[c1,XX,XX]]



b

更新:
我正在使用gfortran(版本5.2.0),部署机器只有从4.6.x开始的版本及更高版本。因此,不幸的是我建议fortran 2008的标准功能无法使用。是否有可能在没有编译器支持它的情况下模仿上述行为?



更新2:
So我结束了实现一个结构如下

 类型Vec_t 
integer,allocatable,dimension(:) :: vec
结束类型Vec_t
类型(Vec_t),可分配,维度(:),目标::数据

我初始化的是这样的(我在最后提到的三角矩阵应用程序)

pre $ allocate(data(max ))
do i = 1,max
allocate(data(i)%vec(i))
end do

和我访问&通过

  print *,data(2)%vec(1)
data(2)%vec (1)= 5

这不正是我之后的事,但对我的应用程序足够好。 / p>

解决方案

让我们看看您想要做什么:

  get(2)= 5 

和错误信息


$ b


错误:(1)处的'get'不是变量

这看起来很全面:你不能做你想做的。或者,也许...



get(2)确实是在Fortran 2003规则下,不是变量。在Fortran 2003中,变量由规则R601和R603给出,它是一个指示符列表。

赋值的左侧必须是一个变量。 / p>

但请看Fortran 2008及其变量的定义。现在一个变量是指定者之一(或与coarrays或复杂部分相关的变量),但也可以是(C602至R602)作为函数引用,其中


应该有一个数据指针结果。


这在Fortran 2008的介绍中进行了总结,详细介绍了扩展在Fortran 2003中,作为


指针函数引用可以表示任何变量定义上下文中的变量。


get(2)是对具有数据指针结果的函数的引用。 get(2)然后可能出现在Fortran 2008规则下的赋值语句的左侧。



唉,对Fortran的这种解释是由当前编译器得不到广泛支持:在回答时只是Cray编译器。



这意味着这个答案实际上是说你有两个选择:切换编译器或等到这个特性更广泛。由于这两种方式都可能不切实际,所以您可能需要另一个答案,它提供了一些稍微便于使用的解决方法。



我更喜欢我的链接 由innoSPG给出,因为虽然后者是基于前者,但适当领域的描述指针函数 - 指针函数ref是一个变量稍微更加清晰。不过,这是一个更方便的文件和一个可行的选择。

As stated in the title, I want to directly modify data that I access through a pointer retrieved from a function. Having a reference returned by a function appearing on the l.h.s. of an assignment(=) is no issue in C++ but the following minimal example in fortran errors out:

module test_mod
  implicit none

  integer, target :: a=1, b=2, c=3 ! some member variables

contains

  function get(i)
    integer, pointer :: get
    integer, intent(in) :: i

    select case (i)
      case (1)
        get => a
      case (2)
        get => b
      case (3)
        get => c
    end select 
  end function get

end module test_mod

program test
  use test_mod
  implicit none
  integer, pointer :: i_p

  !> prints out 1 2 3
  print*, get(1), get(2), get(3)

  !> this is what I want but I get the error
  !> Error: 'get' at (1) is not a variable
  get(2) = 5

  !> this works but is not what I want
  i_p => get(2)
  i_p = 5

end program test

Is there any way to accomplish this behaviour; maybe I'm missing some attributes? I would like to bypass writing any setter routines such as

set(i,value)

since it should mimic the appearance of an array. In my application, the member variables a,b,c are actually arrays of different size

a = [a1, a2, a3]
b = [b1, b2]
c = [c1]

and I want the getter get(i,j) to mimic a matrix of pointers

        j = 1   2   3

i = 1:   [[a1, a2, a3],
i = 2:    [b1, b2, XX],
i = 3:    [c1, XX, XX]]

wehre XX would be referencing to null().

Update: I am using gfortran (version 5.2.0) and the deployment machines would have only versions starting from 4.6.x and upwards. Therefore, the suggested fortran 2008 standard features are unfortunately not available to me. Is it possible to mimic the behaviour described above without having a compiler supporting it out of the box?

Update 2: So I ended up implementing a structure as follows

type Vec_t
  integer, allocatable, dimension(:) :: vec
end type Vec_t
type(Vec_t), allocatable, dimension(:), target :: data

which I initialise like this (my triangular matrix application I mention at the end)

allocate(data(max))
do i=1,max
  allocate(data(i)%vec(i))
end do

and I access & write to it through

print*, data(2)%vec(1)
data(2)%vec(1) = 5

which is not precisely what I was after but good enough for my application.

解决方案

Let's look at what you want to do:

get(2)=5

and the error message

Error: 'get' at (1) is not a variable

That looks pretty comprehensive: you can't do what you want. Or, perhaps...

get(2) is indeed, under the rules of Fortran 2003, not a variable. In Fortran 2003 a variable is given by the rules R601 and R603, which is a list of designators.

The left-hand side of an assignment must be a variable.

But look at Fortran 2008 and its definition of a variable. Now a variable is either one of those same designators (or ones related to coarrays or complex parts), but it could also (C602 to R602) be a function reference which

shall have a data pointer result.

This is summarized in the introduction of Fortran 2008, detailing the extensions over Fortran 2003, as

A pointer function reference can denote a variable in any variable definition context.

get(2) is a reference to a function that has a data pointer result. get(2) then may appear on the left-hand side of an assignment statement under the rules of Fortran 2008.

Alas, this interpretation of Fortran is not widely supported by current compilers: at the time of answering just the Cray compiler.

This means that this answer is really saying that you have two options: switch compiler or wait until this feature is more widespread. As both of these are likely impractical, you probably want another answer which gives something slightly more portable as a workaround.

I prefer my link to that given by innoSPG, as although this latter is based on the former, the description of the appropriate field "Pointer functions - pointer function ref is a variable" is slightly more clear. This is, though, a more accessible document and a viable alternative.

这篇关于在Fortran中有一个函数返回一个可以放在作业左侧的参考的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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