在Fortran中传递派生类型的元素名称

时间:2015-12-17 19:38:09

标签: fortran fortran90

使用Fortran90标准中的代码,有没有办法将派生类型元素的名称传递给Fortran中的子程序?我想做类似以下的事情:

TYPE :: DataContainer
    REAL :: DataElementA
    REAL :: DataElementB
    REAL :: DataElementC
END TYPE DataContainer

SUBROUTINE ComplexOperation(DataMatrixParameter, DataElementName, Parameter)
    ! Parameter Typing for DataElementName?
    DataMatrixParameter%DataElementName = Parameter
END SUBROUTINE

TYPE (DataContainer), DIMENSION :: Data
CALL ComplexMatrixOperation(Data, DataElementA, 5)
CALL ComplexMatrixOperation(Data, DataElementC, 4)

Data%DataElementA5Data%DataElementC4。 DataElementName参数可以是任何类型的元素标识符,但我更愿意避免使用字符串和case语句。那些熟悉C ++的人会将它识别为与成员特征指针直接相似的东西。

我的真正问题当然要比将元素分配给给定值复杂得多。

3 个答案:

答案 0 :(得分:1)

从我可以收集的内容中,您希望能够编写类似

的内容
call ComplexMatrixOperation(Data, DataElementA, ...)

其中Data是一个矩阵,因此子程序看起来像

subroutine ComplexMatrixOperation(matrix, selector, ...)
  type(DataContainer) matrix(:,:)
  something_magical selector

可以根据选择器对matrix(i,j)%DataElementAmatrix(i,j)%DataElementC元素执行操作。

something_magical不存在。但是,您仍然可以选择(超出已经回答的选项)。

我们可以看到DataElementA是一个标量组件,我们可以引用Data%DataElementA,这是一个形状为Data的实数数组。

然后,你可以

call ComplexMatrixOperation(Data%DataElementA, ...)

call ComplexMatrixOperation(Data%DataElementC, ...)

subroutine ComplexMatrixOperation(matrix, ...)
  real matrix(:,:)

如果我们再次假设Data属于等级2(相应地调整)。

答案 1 :(得分:0)

你不能这样做。最好的办法是使用数组而不是命名元素

TYPE :: DataContainer
    REAL, DIMENSION(3) :: DataElement
END TYPE DataContainer

然后将其与

一起使用
SUBROUTINE ComplexOperation(DataMatrixParameter, DataElementIndex, Parameter)
    TYPE(DataContainer) :: DataMatrixParameter
    INTEGER, INTENT(IN) :: DataElementIndex
    REAL, INTENT(IN) :: Parameter
    DataMatrixParameter%DataElement(DataElementIndex) = Parameter
END SUBROUTINE

也许使用像

这样的命名常量
INTEGER, PARAMETER :: DataElementA=1, DataElementB=2, DataElementC=3

用作

CALL ComplexOperation(Data, DataElementC, 1.33)

答案 2 :(得分:0)

尽管可能无法模仿C++ way使用指向类成员的指针,并且目前还没有本地metaprogramming工具(预处理器宏除外),但Fortran却有能力有效地创建类型组件的数组,而不需要任何数组临时(如上所述),这可能对OP的用途很有用。为了说明这一点,下面是一些使用这种组件数组的示例代码:

module testmod
    implicit none
    type A_t
        integer :: u = 0, v = 0
    endtype
    type B_t
        integer :: x = 0, y = 0
        type(A_t) :: a
    endtype

contains
    subroutine setval ( elem, val )
        integer :: elem(:), val    !! assumed-shape array
        elem(:) = val
    endsubroutine

    subroutine setval_2D ( elem, val )
        integer :: elem(:,:), val    !! assumed-shape array
        elem(:,:) = val
    endsubroutine

    subroutine setval_explicit ( elem, n, val )
        integer :: n, elem( n ), val  !! explicit-shape array
        elem( 1:n ) = val
    endsubroutine
end module

program main
    use testmod
    implicit none
    type(B_t), target :: b( 2 ), bmat( 2, 2 )

    !! Pass 1D component arrays.
    call setval ( b(:)% x,     1 )
    call setval ( b(:)% y,     2 )
    call setval ( b(:)% a% u,  3 )
    call setval ( b(:)% a% v,  4 )

    print *, "b( : )% x    = ", b( : )% x
    print *, "b( : )% y    = ", b( : )% y
    print *, "b( : )% a% u = ", b( : )% a% u
    print *, "b( : )% a% v = ", b( : )% a% v
    print *, "b(1) = ", b(1)
    print *, "b(2) = ", b(2)

    !! Pass a 2D component array.
    call setval_2D ( bmat(:,:)% x, 50 )

    print *, "bmat(:,:)% x = ", bmat(:,:)% x

    !! Pass 1D component array sections.
    call setval ( bmat(:, 1)% x, 1 )
    call setval ( bmat(:, 2)% x, 2 )
    call setval ( bmat(2, :)% x, 5 )

    print *, "bmat(:,:)% x = ", bmat(:,:)% x

    !! Pass a 2D component array to an explicit-shape dummy array
    !! (in this case, copy-in/copy-out may occur).
    call setval_explicit ( bmat(:,:)% x, size(bmat), 100 )

    print *, "bmat(:,:)% x = ", bmat(:,:)% x
endprogram

结果

 b( : )% x    =            1           1
 b( : )% y    =            2           2
 b( : )% a% u =            3           3
 b( : )% a% v =            4           4
 b(1) =            1           2           3           4
 b(2) =            1           2           3           4
 bmat(:,:)% x =           50          50          50          50
 bmat(:,:)% x =            1           5           2           5
 bmat(:,:)% x =          100         100         100         100

[附注]有趣的是,元编程如何在动态语言中起作用,例如:与朱莉娅(虽然可能与预处理器宏类似)。

function test( a, fieldname, val )
    @eval $a.$fieldname = $val
end

type Person
    age :: Int
    weight :: Float64
end

foo = Person( 0, 0.0 )

test( foo, :age, 100 )
test( foo, :weight, 789.0 )

@show foo.age
@show foo.weight