"Operation is invalid" 使用 ifort 为派生类型重载加法时
"Operation is invalid" when overloading addition for a derived type using ifort
这是我之前开始的一个话题的后续问题
基本上,我想要实现的是定义一个自动分配原始类型的延迟类型(实数、整数、字符和逻辑)。您可以在下面看到一个工作示例上面的 link 并用 gcc version 7.3.0
和 ifort version 18.0.0
.
编译
我现在已经扩展了代码,以便 "use" 延迟数据类型,但不知道分配的原始类型是什么。这是通过覆盖基本运算符来实现的。为了简单起见,我在以下示例中仅包含 +
运算符。该示例可以使用 gfortran 进行编译,但是在使用 ifort 进行编译时会出现错误:
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 = 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
让我们将这个示例程序简化为更易于管理的内容:
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)
.
即使最初将此方法简单地视为 "compiler bug workaround",在不为加法运算的两边使用无限多态参数的情况下实现定义的运算确实是值得的
当您想创建一个新类型时 mytype2
您不想用函数 plus_func_class
定义操作。不过你需要这样做,因为如果你为泛型 operator(+)
.
创建一个新的特定函数,你将有一个不明确的接口
这是我之前开始的一个话题的后续问题
基本上,我想要实现的是定义一个自动分配原始类型的延迟类型(实数、整数、字符和逻辑)。您可以在下面看到一个工作示例上面的 link 并用 gcc version 7.3.0
和 ifort version 18.0.0
.
我现在已经扩展了代码,以便 "use" 延迟数据类型,但不知道分配的原始类型是什么。这是通过覆盖基本运算符来实现的。为了简单起见,我在以下示例中仅包含 +
运算符。该示例可以使用 gfortran 进行编译,但是在使用 ifort 进行编译时会出现错误:
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 = 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
让我们将这个示例程序简化为更易于管理的内容:
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)
.
即使最初将此方法简单地视为 "compiler bug workaround",在不为加法运算的两边使用无限多态参数的情况下实现定义的运算确实是值得的
当您想创建一个新类型时 mytype2
您不想用函数 plus_func_class
定义操作。不过你需要这样做,因为如果你为泛型 operator(+)
.