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

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

问题描述

在Fortran模块中,我有一个函数,它接受一个数组及其名称,从数据库(实际调用一个C函数)获取数组的形状,将该数组复制到一个临时缓冲区中,并将该缓冲区传递给另一个C函数来处理它。此Fortran函数的名称为整型数据fs_WriteData_i,实型为fs_WriteData_f,双精度型为fs_WriteData_d。所有这些功能不仅可以接受一维阵列,还可以接受2D,3D和4D阵列,并且它们完美地工作。下面是其中一个子例程的接口:

pre $子程序fs_WriteData_d(字段名,数据)
use,intrinsic :: iso_c_binding
隐式无

实数(c_double),维(*)::数据
字符::字段名*(*)

! ...

结束子程序fs_WriteData_d

如果用户调用 fs_WriteData_d('name',data),其中数据是双精度数据,最多为4维数组,这个子例程完成这项工作。现在,我想提供一个通用的重载接口,名为fs_WriteData,所以我使用

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

不幸的是,这不起作用:编译器如果用户只是调用 fs_WriteData('name',data),并且这是因为与所有这些函数的排名不匹配,那么它就无法找到正确的实现。 p>

有没有一种巧妙的方法可以避免使用相同的内容来编写所有fs_WriteData_d_1d,fs_WriteData_d_2d,...子例程,以便使模块更易于维护?



非常感谢。

解决方案

b

正如您发现的,从F2008中为通用调用选择特定过程的规则除了其他要素和要素过程外,还需要Type,Kind和Rank(所谓的TKR兼容)。即使数据伪参数被假定为大小(因此在直接调用特定过程时,它可以与任何非零等级的实际参数相关联),但它仍被认为是TKR兼容性目的的一级参数。



最近发布的Fortran与C的进一步互操作性技术规范(TS29113)增加了假定排名的概念。根据您在 fs_WriteData_d (传递给C的几乎所有可以执行的内容)的可执行部分内执行的操作,可能适用 - Type / Kind / Rank匹配已被扩展,使得假定的等级实际或虚拟参数是兼容的,而不管等级如何。然后编译器的支持是一个相当重要的问题 - 我不认为目前有任何编译器支持这个TS!



对于F201X之前的语言标准编码,有一个很少的可能性:


  • 为每个要支持的等级编写一系列简洁的包装器子例程,然后调用这些包装器子例程一维形式的具体过程,依赖于序列关联将多维数组映射到一维数组。


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

  • b

    这两者的组合可能也是合适的。

    (可能存在第三种选择,使用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天全站免登陆