使用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%DataElementA
为5
,Data%DataElementC
为4
。 DataElementName参数可以是任何类型的元素标识符,但我更愿意避免使用字符串和case语句。那些熟悉C ++的人会将它识别为与成员特征指针直接相似的东西。
我的真正问题当然要比将元素分配给给定值复杂得多。
答案 0 :(得分:1)
从我可以收集的内容中,您希望能够编写类似
的内容call ComplexMatrixOperation(Data, DataElementA, ...)
其中Data
是一个矩阵,因此子程序看起来像
subroutine ComplexMatrixOperation(matrix, selector, ...)
type(DataContainer) matrix(:,:)
something_magical selector
可以根据选择器对matrix(i,j)%DataElementA
或matrix(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