使用ifort

时间:2018-10-03 10:02:32

标签: fortran operator-overloading intel-fortran

这是我较早开始的线程中的跟进问题here.

基本上,我要实现的是定义一个延迟类型,该类型将自动分配原始类型(实数,整数,字符和逻辑)。在上述链接中可以看到一个有效的示例,它用gcc version 7.3.0ifort version 18.0.0编译。

我现在扩展了代码,以便在不知道分配了什么原始类型的情况下“使用”延迟的数据类型。这可以通过覆盖基本运算符来实现。为了简单起见,在下面的示例中,我仅包括了+运算符。该示例可以使用 gfortran 进行编译,但是使用 ifort 进行编译时却给了我一个错误:

  

错误#6303:对于两个操作数的数据类型,赋值操作或二进制表达式操作无效。 [PLUS_FUNC_CLASS]   c%i = a%i + b%i

有人知道这是什么问题吗?我已经在错误中进行了搜索,但是我找不到自己在做什么。


注意

为了匹配精度,我使用了以下编译标志

ifort -r8 -i8 tst.f90

gfortran -fdefault-real-8 -fdefault-integer-8 -fdefault-double-8 tst.f90


这是示例代码:

module DervType

  implicit none

  type, public :: mytype
    real                          :: r
    integer                       :: i
    character(len=:), allocatable :: c
    logical                       :: l
  end type

  interface assignment(=)
    module procedure equal_func_class
  end interface

  interface operator(+)
    module procedure plus_func_class
  end interface

contains

   subroutine equal_func_class(a,b)
        type(mytype), intent(out):: a
        class(*),     intent(in) :: b

        select type (b)
            type is (mytype)
                print *, "is mytype"
                if ( .not. a%r == b%r ) a%r = b%r      !! <-- ugly, but necessary not to end up in an endless loop when reassigning mytype (only testing and assigning real here)
            type is (real)
                print *, "is real"
                a%r = b
            type is (integer)
                print *, "is int"
                a%i = b
            type is (character(len=*))
                print *, "is char"
                a%c = b
            type is (logical)
                print *, "is logical"
                a%l = b 
        end select

    return

  end subroutine equal_func_class


  recursive function plus_func_class(a,b) result(c)
        class(*), intent(in)        :: a
        class(*), intent(in)        :: b
        type(mytype)                :: c

        select type (a)
            type is (mytype)
                print *, "left side is mytype"

                !! -------------------------------
                !! only testing one case here and only real operations are
                !! taken care of!
                !! -------------------------------
                select type (b)
                    type is (mytype)
                        print *, "right side is mytype"                       
                        c%i = a%i + b%i  !! <-- this is where ifort throws the error
                        c%r = a%r + b%r  !! <-- this is where ifort throws the error 
                    type is (real)
                        print *, "right side is real", a%r
                        c = a%r + b
                end select

            !! do similar logic when the operands changing sides
            type is (real)
                print *, "left side is real"
        end select

        !c = 1.

        return        

    end function plus_func_class


end module DervType

program TestType

  use DervType

  implicit none

  type(mytype) :: test, test2, res, res2

  real, parameter :: tt = 2.

  test = 1.
  test = 1
  test = "Hey Tapir"
  test = .true.

  test2 = 2.

  test = test2

  print *, "test = ", test%r

  res  = test + 1.0
  res2 = test + tt

  print *, "Calculation 1 (real) : ", res%r
  print *, "Calculation 2 (real) : ", res2%r

end program TestType

使用gfortran进行编译并运行程序时,将产生以下输出:

 is real
 is int
 is char
 is logical
 is real
 is mytype
 test =    2.0000000000000000     
 left side is mytype
 right side is real   2.0000000000000000     
 is real
 is mytype
 left side is mytype
 right side is real   2.0000000000000000     
 is real
 is mytype
 Calculation 1 (real) :    3.0000000000000000     
 Calculation 2 (real) :    4.0000000000000000 

1 个答案:

答案 0 :(得分:4)

让我们将此示例程序简化为更易于管理的内容:

 module DervType

  implicit none

  type mytype
    integer i
  end type mytype

  interface operator(+)
    module procedure plus_func_class
  end interface

contains

  recursive function plus_func_class(a,b) result(c)
    class(*), intent(in)        :: a
    class(*), intent(in)        :: b
    type(mytype)                :: c

    c%i = 1+1
  end function plus_func_class

end module DervType

我的ifort 18.0.3对此抱怨:

error #6303: The assignment operation or the binary expression operation is invalid for the data types of the two operands.   [PLUS_FUNC_CLASS]
    c%i = 1+1
-----------^

熟悉吗?

好吧,看起来好像是因为我们有plus_func_class的参数,因为无限多态ifort决定将此函数作为带有表达式operator(+)的通用1+1的特定过程。 (删除recursive前缀以查看更多信息。)

我们不希望它那样做。我们可以说服它不这样做吗?

我们希望我们的真函数考虑左侧或右侧为class(mytype)的情况,因为我们不希望重新实现intrinsic+intrinsic。我不会详细说明,但是您可以两次实现该功能:一次使用LHS class(mytype)和RHS class(*),一次使用LHS class(*)和RHS class(mytype)


即使最初只是简单地将这种方法视为“编译器错误解决方法”,也确实值得实现定义的操作,而不必在加法操作的两侧都使用无限多态参数。

当您要创建新类型mytype2时,您不想使用函数plus_func_class定义操作。不过,您需要这样做,因为如果您为通用operator(+)创建新的特定函数,则会有一个模棱两可的接口。