【问题标题】:Initialize parametric-size array of parameterized derived type in Fortran?在Fortran中初始化参数化派生类型的参数大小数组?
【发布时间】:2020-05-25 15:41:59
【问题描述】:

Fortran 允许参数化派生类型元素的大小。但是,在类型声明中可以为固定大小的元素分配默认值的情况下,似乎没有办法用于参数化条目:

PROGRAM main
  IMPLICIT NONE

  TYPE data1
     INTEGER :: array(5) = 2   ! allowed
  END type data1

  TYPE data2(n)
     INTEGER, LEN :: n
     INTEGER :: array(n) = 2   ! incorrect: error #8737 with intel fortran 19,
  END type data2               !            ignored by gfortran 8.2.1

END PROGRAM main

分配默认值很方便,因为它可以避免每次使用类型时都重复初始化,但对于参数大小的字段,这是不允许的; Gfortran 只是默默忽略默认值,Intel Fortran 报错

error #8737: For a default initialized component every type parameter and array bound
             must be a constant expression.   [ARRAY]

是否有任何语法允许定义默认值?

【问题讨论】:

    标签: fortran


    【解决方案1】:

    此类组件不能有默认初始化。

    正如英特尔 Fortran 错误消息所述,具有初始化表达式的组件的数组边界必须是常量表达式(这是 Fortran 2018 的约束 C762)。长度类型参数不能用作常量表达式。

    没有其他语法可以为组件指定默认值。

    种类类型参数可以在常量表达式中使用,因此具有该类型种类参数给定边界的组件可以具有默认初始化。

    【讨论】:

    • 你确定吗? F2018,第 75 页,注 3,似乎不同意。
    • @evets,恐怕我目前无法访问我的最终标准文档,但我检查的草稿版本在注释 3 中没有数组组件。你能提供更多你指的是哪一部分的详细信息? (我看到它有一个具有默认初始化的非恒定长度字符组件,但我认为这是一个错误,在最终版本中已得到纠正。)
    • 注 3,包含 TYPE MEMBER (NAME_LEN) ; INTEGER, LEN :: NAME_LEN ; CHARACTER (LEN = NAME_LEN) :: NAME = '' ; ... 这显示了在规范表达式中使用类型参数的组件初始化。该标准明确规定 类型参数可以用作派生类型定义中规范表达式 (10.1.11) 中的主要参数。 如果转到 10.1.11,则它具有 一个受限制的表达式是一个表达式......每个主要是......(13)一个正在定义的派生类型的类型参数,
    • @evets,恐怕我看不到规范表达式与组件初始化的相关性。当name_len 是使用该组件定义的类型的类型参数时,自然允许使用非常量name_len 作为字符组件长度的规范表达式。但是在默认初始化方面,规范表达式并不重要。 C762 是一个附加约束,这意味着类型参数和数组边界必须是常量表达式,而不是规范表达式。
    • @VladimirF,我同意这可能被错误地省略了,目的是允许integer :: array(n)=0(但不允许integer :: array(n+0)=0integer :: array(2:n+1)=0integer :: array(n)=[(i,i=1,n)]),但我觉得错误地有示例中的长度参数非常量似乎更有可能。
    【解决方案2】:

    您可以创建一个构造函数,该构造函数采用长度参数来创建对象

    module datatypes
    
    type data2(n)
        integer, len :: n
        integer :: array(n)
    contains        
        procedure, pass :: data2_fill2
    end type
    
    interface data2
        module procedure new_data2
    end interface
    
    contains
        subroutine data2_fill2(this)
            class(data2(*)) :: this
            this%array = 2
        end subroutine
        function new_data2(n) result(r)
            integer, intent(in) :: n
            type(data2(n)) :: r
            call r%data2_fill2()
        end function
    end module
    
    program Main
    use datatypes
        type(data2(3)) :: mydata
    
        mydata = data2(100)
    
        print *, "Size of array ", size(mydata%array)
    
        if( mydata%array(1) /= 2) then
            print *, "Something went wrong"
        end if
    
    
    end program
    

    【讨论】:

    • 为什么这么复杂?该标准已经允许组件初始化。
    • 此方法不允许将字段紧凑、非冗余地初始化为我正在寻找的合理值(与未初始化的内存相反)。最值得注意的是,无论使用哪种类型,它都不能保证初始化,就像默认值一样。
    【解决方案3】:

    您在不同的编译器中发现了一个错误。您的代码符合标准。稍微充实一下代码,下面应该打印'2 2 2'。

    program main
    
    implicit none
    !
    ! F2018, 7.5.1, page 64: A derived type can be parameterized by one or
    ! more type parameters, each of which is defined to be either a kind
    ! or length type parameter and can have a default value.
    !
    ! F2018, 7.5.3.1, page 69: A type parameter may be used as a primary in
    ! a specification expression (10.1.11) in the derived-type-def.
    !
    ! 10.1.11 Specification expression (page 156)
    ! ...
    !    R1028 specification-expr  is scalar-int-expr
    !
    ! C1010 (R1028) The scalar-int-expr shall be a restricted expression.
    !
    ! A restricted expression is an expression in which each operation is
    ! intrinsic or defined by a specification function and each primary is
    ! ...
    ! (13) a type parameter of the derived type being defined,
    !
    type data2(n)
       integer, len :: n
       integer :: array(n) = 2
    end type data2
    
    type(data2(n=3)) :: a
    
    print *, a%array  ! This should print 2 2 2
    
    end program main
    

    gfortran 编译代码,但打印 '0 0 0',所以 gfortran 在应用组件初始化时存在错误。

    【讨论】:

    • 请查看我的答案和那里的 cmets,看看为什么我认为这个答案是错误的。但是,我要在这里补充一点,不能孤立地看待规则。在规范表达式中使用长度类型参数是没有争议的(很难理解为什么我们甚至会在没有这种能力的情况下使用长度参数),但是规范表达式不会出现在默认初始化的上下文中。 7.5.3.1 允许我们拥有一个组件 integer :: array(n)(对于 n 一个长度参数),但它没有说明默认初始化,这会受到进一步的限制。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-04
    • 1970-01-01
    • 2019-07-20
    • 1970-01-01
    • 2017-12-13
    相关资源
    最近更新 更多