不同等级的重载fortran接口 [英] Overloaded fortran interface with different ranks

查看:17
本文介绍了不同等级的重载fortran接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 Fortran 模块中,我有一个函数,它接受一个数组及其名称,从数据库(实际上调用一个 C 函数)获取数组的形状,将数组复制到临时缓冲区并将缓冲区传递给另一个 C处理它的函数.此 Fortran 函数的名称为 fs_WriteData_i(用于整数数据)、fs_WriteData_f(用于实数)和 fs_WriteData_d(用于双精度).所有这些函数不仅接受一维数组,还接受 2D、3D 和 4D 数组,并且它们工作得很好.下面是这些子程序之一的接口:

子程序 fs_WriteData_d(fieldname, data)使用,内在 :: iso_c_binding隐式无真实(c_double),维度(*)::数据字符 :: 字段名*(*)!...结束子程序 fs_WriteData_d

如果用户调用 fs_WriteData_d('name', data) 且 data 为双精度,最多为 4 维数组,则此子例程完成.

现在,问题是:我想提供一个名为 fs_WriteData 的通用重载接口,所以我使用

接口 fs_WriteData模块过程 fs_WriteData_i, &fs_WriteData_f, &fs_WriteData_d结束接口 fs_WriteData

不幸的是,这不起作用:编译器指出,如果用户只是调用 fs_WriteData('name', data),它就找不到正确的实现,这是因为排名不匹配所有这些功能.

有没有一种巧妙的方法可以避免编写所有 fs_WriteData_d_1d、fs_WriteData_d_2d、...

非常感谢.

解决方案

排序.

正如您所发现的,从 F2008 开始,为通用调用选择特定过程的规则除其他事项和基本过程外,还需要类型、种类和等级的匹配(所谓的 TKR 兼容).即使假定数据虚拟参数的大小(因此在直接调用特定过程时,它可以与任何非零等级的实际参数相关联),出于 TKR 兼容性的目的,它仍被视为等级一的参数.

最近发布的关于 Fortran 与 C 的进一步互操作性的技术规范 (TS29113) 增加了假定等级的概念.根据您在 fs_WriteData_d 的可执行部分中执行的操作(传递给 C 几乎是您可以做的所有事情)可能适合 - 类型/种类/等级匹配的规则已经扩展,假设无论等级如何,rank 实际或虚拟参数都是兼容的.相当重要的问题是编译器支持——我认为目前没有任何编译器支持这个 TS!

对于 F201X 之前的语言标准编码,有几种可能性:

  • 为您想要支持的每个等级编写一系列瘦包装子例程,然后这些包装子例程调用一维形式的特定过程,依靠序列关联将多维数组映射到一维数组.

  • 将子程序的主体放在一个单独的文件中,并将该文件包含在每个等级的子程序的骨架接口中.这种方法要求子程序主体内的代码在词法上是独立的.在某些情况下,代码也可以以独立于类型的方式编写,您可以使用一个通用的包含文件来处理您想要支持的各种类型.虽然这消除了与复制和粘贴"代码的变更管理相关的问题,但处理 INCLUDE 文件可能有点麻烦.

两者的某种组合也可能是合适的.

(可能存在第三种选择,使用 C 互操作性将针对每个等级和类型组合编写的接口主体的绑定名称设置为一个实现过程的绑定名称,但我不确定是否(ab)使用 C 互操作性是合法的.)

如果不同类型变体的通用命名是您所追求的,那么另一种可能性(再次取决于您在正文中执行的操作)是将数据参数作为 ISO_C_BINDING 内部模块中的 C_PTR 并推送要求将实际参数的 C_LOC 带回子例程的客户端代码中.

In a Fortran module I have a function that takes an array and its name, gets from a database (actually calling a C function) the shape of the array, copies the array in a temporary buffer and passes the buffer to another C function that processes it. This Fortran function has the name fs_WriteData_i for integer data, fs_WriteData_f for real and fs_WriteData_d for double precision. All these functions accept not only one-dimensional arrays, but also 2D, 3D and 4D arrays and they work perfectly. Here follows the interface of one of these subroutines:

subroutine fs_WriteData_d(fieldname, data)
    use, intrinsic :: iso_c_binding
    implicit none

    real(c_double), dimension(*) :: data
    character                    :: fieldname*(*)

    ! ...

end subroutine fs_WriteData_d

If the user calls fs_WriteData_d('name', data) with data being a double precision, up to 4-dimensional array, this subroutine does the job.

Now, to the question: I want to provide a common overloaded interface called fs_WriteData, so I use

interface fs_WriteData
    module procedure fs_WriteData_i, &
                     fs_WriteData_f, &
                     fs_WriteData_d
end interface fs_WriteData

Unfortunately, this does not work: the compiler states that it cannot find the correct implementation if the user just calls fs_WriteData('name', data), and this because of a rank mismatch with all of these functions.

Is there a clever way to avoid writing all the fs_WriteData_d_1d, fs_WriteData_d_2d, ... subroutines with just the same content in order to make the module more maintainable?

Many thanks in advance.

解决方案

Sort of.

As you've discovered, the rules for selection of a specific procedure for a generic call as of F2008 require, amongst other things and elemental procedures aside, a match of Type, Kind and Rank (so called TKR compatible). Even though the data dummy argument is assumed size (so in a direct call to a specific procedure it can be associated with an actual argument of any non-zero rank) it is still considered a rank one argument for TKR compatibility purposes.

The recently published Technical Specification on Further Interoperability of Fortran with C (TS29113) adds the concept of assumed rank. Depending on what you do inside the executable part of fs_WriteData_d (passing to C is pretty much all that you can do) that may suit - the rules for Type/Kind/Rank matching have been extended such that assumed rank actual or dummy argument is compatible regardless of rank. The rather significant issue is then compiler support - I don't think there are any compilers that currently support this TS!

For coding to language standards pre-F201X there are a few possibilities:

  • Write a series of thin wrapper subroutines for each rank that you want to support, with those wrapper subroutines then calling the specific procedure for the 1D form, relying on sequence association to map the multidimensional arrays down to a 1D array.

  • Place the body of the subroutine inside a separate file, and INCLUDE that file inside skeleton interfaces for subroutines for each rank. This approach requires that the code inside the body of the subroutine be lexically rank independent. In some cases the code can also be written in a type independent manner and you can use a common include file for the various types that you want to support. While this eliminates the problems associated with change management of "copy and pasted" code, dealing with INCLUDE'd files can be a bit of a pain.

Some combination of the two may also be suitable.

(A third option possibly exists, to use C interoperability to set the binding name for interface bodies written for each rank and type combination to be the binding name of one implementation procedure, but I'm not sure whether that (ab)usage of C interoperability is legal.)

If common naming for the different type variants is all you are after, then another possibility (again, depends on what you are doing in the body) is to take the data argument as a C_PTR from the ISO_C_BINDING intrinsic module and push the requirement for taking C_LOC of the actual argument back into client code of the subroutine.

这篇关于不同等级的重载fortran接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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