Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

void pointer?

Julian_H_
Beginner
1,122 Views

Hello,

I have a problem I would like to solve but somehow I struggle.

I have different types defined:

! Type KUGS ([KUG]el cheibe)
	TYPE, PUBLIC :: typeKUGS
		CHARACTER(4) :: cIdent	= 'KUGS'
		CHARACTER(4) :: cANam	= ''
		CHARACTER(4) :: cMant	= ''
		CHARACTER(4) :: cMat	= ''
		CHARACTER(4) :: cSpaw	= ''
		TYPE(typeKOOS) :: KOOS_P1, KOOS_P2
		REAL(8) :: rR1 = -1._dp, rR2 = -1._dp
		REAL(8) :: rS1 = -1._dp, rS2 = -1._dp
		REAL(8) :: rRKug
		
		CONTAINS	
			PROCEDURE, PUBLIC::setKUGS => setKUGS_sub
	END TYPE typeKUGS
		
	! Type TORS ([TOR]us cheibe)	
	TYPE, PUBLIC :: typeTORS
		CHARACTER(4) :: cIdent	= 'TORS'
		CHARACTER(4) :: cANam	= ''
		CHARACTER(4) :: cMant	= ''
		CHARACTER(4) :: cMat	= ''
		CHARACTER(4) :: cSpaw	= ''
		TYPE(typeKOOS) :: KOOS_P1, KOOS_P2
		REAL(8) :: rR1 = -1._dp, rR2 = -1._dp
		REAL(8) :: rS1 = -1._dp, rS2 = -1._dp
		REAL(8) :: rRtor
		
		CONTAINS
			PROCEDURE, PUBLIC::setTORS => setTORS_sub
		END TYPE typeTORS

Now I want to define the type typeVAM1 which should have a pointer pointing to a typeKUGS, typeTORS or some other type, but from what I know a pointer always have to be of the same variable type as the target

! Type VAM1 
		TYPE, PUBLIC :: typeVAM1
			CHARACTER(4) :: cIdent	= 'VAM1'
			CHARACTER(4) :: cVNam	= ''
			CHARACTER(1) :: cVTyp	= ''
			CHARACTER(1) :: cMIA	= ''
			CHARACTER(4) :: cVA		= ''
			CHARACTER(4) :: cPA		= ''
			CHARACTER(4) :: cMV		= ''
			CHARACTER(4) :: cVTNa	= ''
			REAL(8) :: rFBAln		= -1._dp
			REAL(8) :: rFBAls		= -1._dp
			REAL(8) :: rEckD		= 0._dp
			REAL(8) :: rArov		= -1._dp
			REAL(8) :: rSFak		= -1._dp
			VOID, POINTER :: pKVNa	! this should point to typeKUGS or typeTORS etc...
			REAL(8) :: rAriv		= 0._dp
			INTEGER :: iMaNv		= 0
			
		CONTAINS
			PROCEDURE, PUBLIC::setVAM1 => setVAM1_sub
		END TYPE typeVAM1

Does someting like a void pointer exist or someone has an other idea to solve this?

0 Kudos
1 Solution
Steve_Lionel
Honored Contributor III
1,122 Views

A couple of options. a CLASS(*) pointer can point to any type. It carries the type info with it. Another option is to use type C_PTR from ISO_C_BINDING, use C_LOC to assign it and C_F_POINTER to "cast" to the desired type. An issue with CLASS(*) is that if you want to use the pointer you will have to do so within a SELECT TYPE construct.

View solution in original post

0 Kudos
6 Replies
Steve_Lionel
Honored Contributor III
1,123 Views

A couple of options. a CLASS(*) pointer can point to any type. It carries the type info with it. Another option is to use type C_PTR from ISO_C_BINDING, use C_LOC to assign it and C_F_POINTER to "cast" to the desired type. An issue with CLASS(*) is that if you want to use the pointer you will have to do so within a SELECT TYPE construct.

0 Kudos
FortranFan
Honored Contributor II
1,122 Views

As shown in the original post, the two types (typeKUGS and typeTORS) look the same, only the values of components seem to differ, implying two object instances of the same type.  Can you not look into this and check whether a TYPE(..) component in typeVAM1 would be a better choice?

0 Kudos
Julian_H_
Beginner
1,122 Views

FortranFan wrote:

As shown in the original post, the two types (typeKUGS and typeTORS) look the same, only the values of components seem to differ, implying two object instances of the same type.  Can you not look into this and check whether a TYPE(..) component in typeVAM1 would be a better choice?

Yeah the example is simplified, my fault. The other types are looking totally different.

0 Kudos
Julian_H_
Beginner
1,122 Views

Steve Lionel (Ret.) wrote:

A couple of options. a CLASS(*) pointer can point to any type. It carries the type info with it. Another option is to use type C_PTR from ISO_C_BINDING, use C_LOC to assign it and C_F_POINTER to "cast" to the desired type. An issue with CLASS(*) is that if you want to use the pointer you will have to do so within a SELECT TYPE construct.

Thanks once again. I will give  the class(*) a try.

---------------------------

Trying:

!+------------------------------------------------------------------------+
	SUBROUTINE findSuperelement_sub(this, cANam, lIsFound, SU)
		IMPLICIT NONE
	
		CLASS(typeSIP), INTENT(IN) :: this
		CHARACTER(4), INTENT(IN) :: cANam
		LOGICAL, INTENT(OUT) :: lIsFound
		CLASS(*), POINTER, INTENT(OUT) :: SU(:)
        TYPE(typeKOZE),  TARGET :: KOZE
		
		lIsFound = .FALSE.
		
		CALL this%findKOZE(cANam, lIsFound, KOZE)
		IF (lIsFound) THEN
            ALLOCATE(TYPE(typeKOZE)::SU(1))
            SELECT TYPE(SU)
                TYPE IS (typeKOZE)
                    SU(1) => KOZE
                    
                CLASS DEFAULT
                    WRITE(*,*) 'eleganter Error'                
            END SELECT
			RETURN
        END IF
!+------------------------------------------------------------------------+
	SUBROUTINE findSuperelement_sub(this, cANam, lIsFound, SU)
		IMPLICIT NONE
	
		CLASS(typeSIP), INTENT(IN) :: this
		CHARACTER(4), INTENT(IN) :: cANam
		LOGICAL, INTENT(OUT) :: lIsFound
		CLASS(*), POINTER, INTENT(OUT) :: SU
        TYPE(typeKOZE),  TARGET :: KOZE
		
		lIsFound = .FALSE.
		
		CALL this%findKOZE(cANam, lIsFound, KOZE)
		IF (lIsFound) THEN
            SU => KOZE
			RETURN
        END IF
	END SUBROUTINE findSuperelement_sub

I tried the concept but I guess I still do not understand it fully. This is my try. The pointer pKOZE => KOZE is pointing correctly, but the allocaten of the CLASS(*) SU is not working. Any suggestions what I am doing wrong?

 

I found online this example

class(*), pointer :: v1, v2(:)
type(person), target :: p1
real, pointer :: r1(:)
v1 => p1
allocate(real :: v2(10))
select type (v2)
type is (real)
r1 => v2
class default
stop 'Error in type selection'
end select

SOURCE: http://www.training.prace-ri.eu/uploads/tx_pracetmo/AdvFTN_handout.pdf

so the select type construct has to be used just in the case I have to allocate an array?

0 Kudos
IanH
Honored Contributor II
1,122 Views

The first subroutine in #5 should not compile.  It has syntax that attempts to pointer assign to an array element.  Array elements in Fortran are never pointers. 

In the first subroutine, `SU` is a pointer array.  It can be pointed at other arrays - `su => some_other_array`.

If you want an array that has a pointer for each element, then the array needs to be of a derived type with a pointer component.

type :: t
  ! Pointer to a scalar of any type.
  class(*), pointer :: item => null()
end type t

type(t) :: array(2)

type(x), target :: some_scalar
type(y), target :: another_scalar

array(1)%item => some_scalar
array(2)%item => another_scalar

You don't have to use select type to allocate a polymorphic array - depending on the language revision you are targeting (and whether your compiler supports those revisions) other options exist, including perhaps just using an assignment statement.

It isn't totally clear to me what you are trying to do - consider providing more explanation.

0 Kudos
Julian_H_
Beginner
1,122 Views

ianh wrote:

The first subroutine in #5 should not compile.  It has syntax that attempts to pointer assign to an array element.  Array elements in Fortran are never pointers. 

In the first subroutine, `SU` is a pointer array.  It can be pointed at other arrays - `su => some_other_array`.

If you want an array that has a pointer for each element, then the array needs to be of a derived type with a pointer component.

type :: t
  ! Pointer to a scalar of any type.
  class(*), pointer :: item => null()
end type t

type(t) :: array(2)

type(x), target :: some_scalar
type(y), target :: another_scalar

array(1)%item => some_scalar
array(2)%item => another_scalar

You don't have to use select type to allocate a polymorphic array - depending on the language revision you are targeting (and whether your compiler supports those revisions) other options exist, including perhaps just using an assignment statement.

It isn't totally clear to me what you are trying to do - consider providing more explanation.

 

By the subroutines in #5 I just try to understand the concept which Lionel explained. His answer was quite short but pointed in the right direction, so I searched for more information and found the last example in #5. I tried to copy the concept . The subrouteine findSuperelement_sub is not complete yet. cANam is a unique string. For this string is searched in different types (for now just all Objects of typeKOZE but there will be more types). Because of this is neccessary that the subroutine findSuperelemnt_sub has the capability to return CLASS(*) because in the subroutine itself its determiend which Object type will be returned. 

For this "Superelement" is searched so I can point from the typeVAM1 to it, thats what I wrote in my initial post.

0 Kudos
Reply