Reputation: 1525
I want to have a subroutine that converts a contents of a numeric string to a numeric type (int, real, double precision, real(real128)).
However I am getting an error when trying to use Class(*)
. The error
is shown below:
gfortran -o build/lib/larsa.o -c -ffree-form -g -J./build/lib lib/larsa.f
lib/larsa.f:1933.35:
Read (s, frmt, iostat=ios) num
1
Error: Data transfer element at (1) cannot be polymorphic unless
it is processed by a defined input/output procedure
lib/larsa.f:1935.32:
Read (s, *, iostat=ios) num
1
Error: Data transfer element at (1) cannot be polymorphic unless
it is processed by a defined input/output procedure
This is the subroutine I have written.
Subroutine converts_str_to_num &
( &
s, num, &
fmt, wrn &
)
Character (len=*), Intent (in) :: s
Character (len=*), Intent (in), Optional :: fmt
Class (*) :: num
Character (len=*), Intent (inout), Optional :: wrn
Integer :: ios
Character (len=65) :: frmt
!!$ Reads contents of s and puts value in i.
If (Present (fmt)) Then
frmt = "(" // Trim (fmt) // ")"
Read (s, frmt, iostat=ios) num
Else
Read (s, *, iostat=ios) num
End If
End Subroutine converts_str_to_num
Upvotes: 1
Views: 786
Reputation: 32366
To tidy up the comments, I'll provide an answer.
The error message is clear: you cannot have a polymorphic variable in an input/output list unless the list is processed by defined input/output. This is 9.6.3.5 in Fortran 2008. class(*) num
is (unlimited) polymorphic.
Now, for polymorphic derived types you could define such a defined input/output procedure, but that counts as a lot of work and gfortran certainly doesn't (yet) support that notion. Also, you can't do this for intrinsic types. These factors mean you have to deal with non-polymorphic variables in the input list you have.
Of course, it's possible to use generics to avoid polymorphism, but the alternative (as it is for about everything polymorphic) is to use a select type
construct. For simplicity, ignore the list-directed and explicit format cases:
select type (assoc => num)
type is (int)
Read (s, *, iostat=ios) assoc
type is (real)
...
type is (...)
class default
error stop "Oh noes!"
end select
I've used an associate name in the select type to address one part of your confusion. If you've just done
select type(num)
type is (int)
Read (s, *, iostat=ios) num
end select
to think that "now using num
is fine: why?" that's because the num
inside the construct is not the same as the num
outside. Crucially, it isn't polymorphic but is the exact type matching the type is
.
Upvotes: 4