如何在Fortran中初始化参数化派生类型的参数大小数组?

6

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]

有没有一种语法,可以在所有内容之后定义默认值?
3个回答

2

这类组件不能进行默认初始化。

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

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

kind类型参数可以出现在常量表达式中,因此由该类型的kind参数给出边界的组件可以进行默认初始化。


@evets,恐怕我现在无法访问我的最终标准文档,但是我检查过的草稿版本中,在注释3中没有数组组件。您能否提供更多关于您所指的部分的详细信息?(我看到它具有非常量长度字符组件,并带有默认初始化,但我认为这是一个错误,在最终版本中已经得到了纠正。) - francescalus
1
注意3,包含TYPE MEMBER (NAME_LEN) ; INTEGER, LEN :: NAME_LEN ; CHARACTER (LEN = NAME_LEN) :: NAME = '' ; ...。这显示了组件初始化,其中类型参数用于规范表达式。标准明确指出“在派生类型定义中,类型参数可以用作规范表达式(10.1.11)中的主要表达式。”如果您转到10.1.11,则会发现“受限制的表达式是一个表达式...每个主要表达式都是...(13)正在定义的派生类型的类型参数”。 - evets
1
@evets,恐怕我没有看到规范表达式与组件初始化相关的关系。当name_len是定义该组件的类型的类型参数时,将非常量的name_len用作字符组件长度的规范表达式是自然允许的。但是,当涉及到默认初始化时,规范表达式并不重要。C762是一个额外的约束条件,这意味着类型参数和数组边界必须是常量表达式,而不是规范表达式。 - francescalus
我看到了 character(name_len) :: name=''。但是我也看到了 C762,如果它与注释中的示例存在冲突(即使该注释是规范性的),则必须使用 C762。您对 C762 的看法是什么?为什么它在这种情况下不适用? - francescalus
1
@VladimirF,我同意这可能是一个错误遗漏,本意是允许integer :: array(n)=0(但不包括integer :: array(n+0)=0integer :: array(2:n+1)=0integer :: array(n)=[(i,i=1,n)]),但我认为在示例中错误地将长度参数设置为非常量更有可能。 - francescalus
显示剩余9条评论

0
你可以创建一个构造函数,该函数接受长度参数以创建对象。
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

为什么这么复杂?标准已经允许组件初始化了。 - evets
这种方法不允许以紧凑、非冗余的方式初始化字段为合理的值(与未初始化的内存相反),而我正在寻找这种方法。最值得注意的是,它不能保证无论类型的使用情况如何都会进行初始化,就像默认值一样。 - kdb

0
你在不同的编译器中发现了一个错误。你的代码符合标准规范。稍微完善一下代码,应该会输出'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在应用组件初始化时存在错误。


2
请查看我的答案和评论,了解我为什么认为这个答案是错误的。然而,我想在这里补充一点,就是我们不能孤立地看待规则。在规范表达式中使用长度类型参数是毫无争议的(在没有这种能力的情况下,我们甚至不知道为什么会有长度参数),但规范表达式不出现在默认初始化的上下文中。7.5.3.1 允许我们拥有一个组件 integer :: array(n)(其中 n 是一个长度参数),但它对于默认初始化没有任何说明,因为默认初始化受到进一步的限制。 - francescalus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接