Fortran 派生类型:重载赋值运算符不适用于“参数”属性

Posted

技术标签:

【中文标题】Fortran 派生类型:重载赋值运算符不适用于“参数”属性【英文标题】:Fortran derived types: Overloaded assignment operator not working with 'PARAMETER' attribute 【发布时间】:2014-10-19 04:08:28 【问题描述】:

我正在使用派生类型(bicomplex)和赋值运算符(=)的重载,因此可以将real*8 分配给bicomplex。 bicplx模块的MWE如下:

MODULE bicplx

  type bicomplex
    COMPLEX*16 :: a
    COMPLEX*16 :: b
  end type

  interface assignment(=)
    module procedure dble_assign_bicplx
  end interface

contains

  subroutine dble_assign_bicplx(qleft, xright) 
    implicit none         
    type(bicomplex), intent(out) :: qleft
    double precision, intent(in) :: xright

    qleft%a = xright
    qleft%b = 0.0d0          
    return
  end subroutine dble_assign_bicplx

end MODULE

实数到复数的赋值由 Fortran 固有地处理。此方法在用于“典型”双复变量时效果很好,但当我想将 real*8 分配给具有 PARAMETER 属性的双复时会中断:

TYPE(bicomplex) :: test1
test1 = 1.d0

完美运行,但是:

TYPE(bicomplex), parameter :: test1 = 1.d0

无法编译并给出 2 个错误:Error: Incompatible derived type in PARAMETER at (1)Error: Can't convert REAL(8) to TYPE(bicomplex) at (1)。 然而,

TYPE(bicomplex), parameter :: test1 = bicomplex(1.d0, 0.d0)

完美运行。

我是否遗漏了什么,或者它是标准的一部分,不能通过使用重载赋值运算符来分配参数?理想情况下,我想使用 F90/F95(而不是 2003 或 2008)来解决这个问题。

【问题讨论】:

我认为它必须是一个函数type(bicomplex) function dble_assign_bicplx(qleft, xright) 如果定义的赋值是由函数指定的,那么你将如何控制函数结果的赋值到赋值左侧的东西上? 【参考方案1】:

“参数”是一个命名常量。该语言的规则要求命名常量的值可以在“编译时”确定 - 即在程序执行之前。这意味着用于赋予命名常量其值的表达式需要能够在编译时确定。在最近的标准中,这方面的语言术语是“常量表达式”,在早期的标准中,它也被称为“初始化表达式”(可以用作初始化程序 - 在程序执行之前)。

定义的赋值是一个可执行的动作——当程序运行时,它会执行位于定义赋值后面的过程中的语句。这不是通常可以在编译时完成的事情。

正如您所发现的,您可以使用结构构造函数,其中组件初始化器是常量表达式来初始化派生类型命名的常量。

【讨论】:

【参考方案2】:

我对该标准的解读是,这里不能使用已定义的运算符。我的想法是,这是因为运算符用于 defined assignment,其中使用了命名常量 initialization(参见 Fortran 2008 的 R503 和 C507,第 5.2.1 节) .

在 Fortran 2008 第 5.2.3 节中,关于初始化:

如果初始化为=constant-expr,则变量初始定义为constant-expr指定的值;如有必要,根据内在赋值的规则转换值

在该段落(未显示)中可能存在一些歧义,因为它以引用实体没有parameter 属性开头。因此,请看第 5.3.13 节中的 parameter 属性:

实体具有由其constant-expr指定的值,必要时转换为实体的类型、类型参数和形状。

但是,第 5.4.11 节(对于 parameter 语句)可能会强调这种转换是通过内在赋值进行的:

每个命名常量的值由对应的常量表达式指定;如有必要,根据内在赋值的规则转换值

对于第一个命名常量情况,没有从内在类型到派生类型的内在赋值。在第二种情况下,使用派生类型的构造函数,确实使用了内在赋值。

【讨论】:

谢谢!所以没有办法在不使用 bicomplex() 运算符的情况下创建一个名为常量的双复数?这很不方便...... 这个答案有点混乱和徘徊:我会留下我的想法并欢迎评论。 francescalus 第一次做对了。初始化中的 = 不是赋值,它是引入初始化值的语法。在这种情况下,bicomplex() 是一个结构构造函数,实际上在这种情况下没有其他方法可以创建该类型的值。

以上是关于Fortran 派生类型:重载赋值运算符不适用于“参数”属性的主要内容,如果未能解决你的问题,请参考以下文章

赋值运算符重载有类似的转换(仅在 VS 中)

C++ - 让派生类从基类“继承”重载赋值运算符的安全/标准方法

Fortran 派生类型运算符

派生类型中的可变长度数组

重载赋值运算符 - 多态容器

C++的=重载问题,怎样为两个有相同成员的类赋值