Reputation: 123
As I understand, a user-derived type's definition can't contain target
attributes. E.g., this isn't allowed:
type TestType
integer, target :: t
end type
However, it's fine for them to be a pointer:
type TestType2
integer, pointer :: p
end type
My question is, then, how can one use a pointer to point at an object's type variable? For example, if I wanted an object of type(TestType2)
to have its p
variable point to an object of type(TestType)
's t
variable, how would I go about this? For example:
type(TestType) :: tt
type(TestType2) :: tt2
tt%t = 1
tt%p => tt%t
Thanks!
Upvotes: 3
Views: 570
Reputation: 123
Thanks @roygvib and @Vladimir F, I hadn't realised that giving the whole object variable the target
attribute would allow me to point to any of its components. That worked perfectly.
For posterity, as my use case was a little more complex than the example above, I thought I'd post a more representative example of what I was trying to achieve. I was creating a grid system containing GridCell
s and River
s, each GridCell having an array of Rivers, and each River also having an array of Rivers that flow into in (inflows
) - these inflows would be Rivers that have been previously created and stored in the GridCell's array of rivers. I wanted to use pointers so that the inflows could just point to the corresponding river in a particular GridCell's rivers array.
The added complication is that River
itself is an abstract type, extended by different SubRiver
s (SubRiver1 and SubRiver2 in the example below). I wanted the arrays of rivers and inflows to be of class(River)
(i.e., polymorphic) and the only way to achieve that without Fortran complaining about polymorphic arrays was to create another user-derived type RiverElement
with a polymorphic class(River), allocatable :: item
property to store the river (see here).
Finally, because I couldn't set the inflows
array such that each item was a pointer (setting inflows(:)
as a pointer makes a pointer array, not an array of pointer), I had to create another user-derived type specifically for storing pointers to Rivers.
Here's the module with all the type definitions:
module TestModule
implicit none
type :: RiverPointer
class(River), pointer :: item => null()
end type
type, abstract :: River
type(RiverPointer), allocatable :: inflows(:)
integer :: id
end type
type :: RiverElement
class(River), allocatable :: item
end type
type :: GridCell
type(RiverElement), allocatable :: rivers(:)
end type
type, extends(River) :: SubRiver1
end type
type, extends(River) :: SubRiver2
end type
end module
And here's a test program showing that it works:
program main
use TestModule
implicit none
type(GridCell), target :: gc
type(SubRiver1) :: sr1
type(SubRiver2) :: sr2
type(SubRiver1) :: sr3
sr1%id = 1
sr2%id = 2
sr3%id = 3
allocate(gc%rivers(3))
allocate(gc%rivers(1)%item, source=sr1)
allocate(gc%rivers(2)%item, source=sr2)
allocate(gc%rivers(3)%item, source=sr3)
allocate(sr3%inflows(2))
sr3%inflows(1)%item => gc%rivers(1)%item
sr3%inflows(2)%item => gc%rivers(2)%item
write(*,*) sr3%inflows(1)%item%id ! 1
write(*,*) sr3%inflows(2)%item%id ! 2
gc%rivers(1)%item%id = 100
write(*,*) sr3%inflows(1)%item%id ! 100
end program
Thanks all!
Upvotes: 0
Reputation: 60088
There would be very little sense in
type TestType
integer, target :: t
end type
because values of type(TestType)
may easily come up in contexts where
they cannot be a target of a pointer.
As @roygvib comments, you have to give the target
attribute to the whole object variable:
type(TestType), target :: tt
then you can make pointers to any of its components.
I could imagine that one could allow giving the target attribute to allocatable structure components in the type declaration, but it is not allowed. Certainly that would not make good sense for regular components.
Upvotes: 3