I am encountering an error with the function detailed in this post.
The problem occurs because I am trying to return a type corresponding to the input types. Can anyone suggest a solution? I originally had a function for each type, and then a generic interface to group them into the same name. Now I am trying to put everything in a single function using polymorphism.
Here is the error that gfortran is giving me.
gfortran -o build/lib/foul.o -c -ffree-form -g -J./build/lib lib/foul.f
lib/foul.f:471.45:
Function cassign (expr, a, b, wrn) Result (c)
I have tried to use an allocatable array. In the main program I then do
Character (len=65), Allocatable :: sc(:)
Integer, Allocatable :: ic(:)
Real, Allocatable :: rc(:)
Allocate (sc(1))
Allocate (ic(1))
Allocate (rc(1))
sc = cassign (ra < rb, sa, sb)
ic = cassign (ra < rb, ia, ib)
rc = cassign (ra < rb, ra, rb)
This returns the following error
gfortran -o build/utests/test_foul.o -c -ffree-form -g -J./build/lib utests/test_foul.f utests/test_foul.f:315.7:
sc = cassign (ra < rb, sa, sb)
1
Error: Can't convert CLASS(*) to CHARACTER(1) at (1)
utests/test_foul.f:316.7:
ic = cassign (ra < rb, ia, ib)
1
Error: Can't convert CLASS(*) to INTEGER(4) at (1)
utests/test_foul.f:317.7:
rc = cassign (ra < rb, ra, rb)
1
Error: Can't convert CLASS(*) to REAL(4) at (1)
1
Error: CLASS variable 'c' at (1) must be dummy, allocatable or pointer
lib/foul.f:495.10:
c = a
1
Error: Nonallocatable variable must not be polymorphic in intrinsic
assignment at (1) - check that there is a matching specific subroutine
for '=' operator
lib/foul.f:497.10:
c = b
1
Here is the function I have coded. The variables a and b can be any of the types
Character, integer or real. And the output type should match the inputs a and b
The function type_match (a, b) returns true if the two types match, false otherwise.
Function cassign (expr, a, b, wrn) Result (c)
Logical, Intent(in) :: expr
Class (*), Intent(in) :: a, b
Logical, Intent (out), Optional :: wrn
Class (*) :: c
Logical :: warn, tma, tmb
!!$ Perform warning tests (performs type matching).
If (Present (wrn)) Then
!!$ Matching input types.
tma = type_match (a, b)
if (tma) Then
tmb = type_match (a, c)
!!$ Matching input and output types.
If (tmb) Then
If (expr) Then
c = a
Else
c = b
End If
wrn = .False.
!!$ Warning: Non-matching types.
Else
wrn = .True.
End If
Else
wrn = .True.
End If
Else
If (expr) Then
c = a
Else
c = b
End If
End If
End Function cassign
I am not sure that I recommend doing what I write below, preferring instead keeping to generics, but I will attempt to explain.
The first thing to note is that, as the error message states, for a non-dummy argument polymorphic variable (such as c) that variable must have the pointer or allocatable attribute. Here, it makes sense for the function result to be allocatable.
After adding the allocatable attribute, you seem to experience two things related to assignment of the allocatable polymorphic variable: once in the function setting the result, and once using the result of the function.
The version of gfortran you are using doesn't (apparently) support intrinsic assignment to polymorphic variables. You can use the equivalent, which arguably has the intention even clearer:
allocate (c, source=a) ! You may also need to provide bounds for c
! for some gfortran.
This is the solution to the assignment problem in the function.
With the function result, however, you are now returning a polymorphic result. That means that the variable taking the assignment must also be polymorphic, or the assignment must not be intrinsic. This is the
Error: Can't convert CLASS(*) to INTEGER(4) at (1)
error when you try intrinsic assignment.
Either make everything polymorphic, stick with generics, or use defined assignment. A simplified example follows for the latter case. [Adjust and extend as required.]
module hello_bob
interface assignment(=)
module procedure int_equal_func_class
end interface
contains
subroutine int_equal_func_class(a,b)
integer, intent(out) :: a(:)
class(*), intent(in) :: b(:)
select type (b)
type is (integer)
a = b
end select
end subroutine int_equal_func_class
function func(a)
class(*), intent(in) :: a(:)
class(*), allocatable :: func(:)
! No intrinsic assignment supported, also see note about bounds
allocate(func, source=a)
end function func
end module hello_bob
program bob
use hello_bob
integer i(4)
i=func([1,2,3,4])
print*, i
end program bob
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With