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

Fortran Optional Arguments

Vasili_M_
初學者
2,665 檢視
I have a subroutine splits_str_to_int (s, delim, t1, t2, t3, t4, t5), where 
t2, t3, t4, and t5 are optional. I am creating a wrapper around it.

When using optional arguments in the wrapper subroutine, do I need to check
whether the arguments are present first?.

<code>Subroutine splits                    &
  (                                  &
    s, delim,                        &
    t1, t2, t3, t4, t5, t6, t7, t8,  & 
    pos                              &
  )

Character (len=*), Intent (in) :: s, delim
Character (len=*), Intent (in), Optional :: pos

Integer, Intent (out) :: t1
Integer, Intent (out), Optional :: t2, t3, t4, t5, t6, t7, t8

Integer :: nf

If (Present (t2)) Then    
  Call splits_str_to_int (s, delim, t1, t2)
Else If (Present (t3)) Then    
  Call splits_str_to_int (s, delim, t1, t2,t3)
Elre If (Present (t4)) Then    
  Call splits_str_to_int (s, delim, t1, t2, t3, t4)
Else If (Present (t5)) Then    
  Call splits_str_to_int (s, delim, t1, t2, t3, t4, t5)
End If

</code>
0 積分
1 解決方案
mecej4
榮譽貢獻者 III
2,665 檢視

To the extent that optional arguments that may or may not be present can be passed along as actual arguments to other routines, yes. However, there are certain rules regarding optional arguments that your code does not satisfy. You have to provide explicit interfaces, and use the keyword=value form when arguments cannot be associated by position in the argument list.

Try the following fixed-up version. In the last call to "splits", "pos=pos" could be replaced by just "pos".

Program Test
  implicit none
  integer s, delim,sn,pos,t1,t2,t3,t4,t5,t6,t7,t8,t9

  Call splits (s, delim, sn=sn)
  Call splits (s, delim, sn=sn, pos=pos)
  Call splits (s, delim, t1, t2)
  Call splits (s, delim, t1, t2, pos=pos)
  Call splits (s, delim, t1, t2, t3, t4, t5, t6, t7, t8, t9)
  Call splits (s, delim, t1, t2, t3, t4, t5, t6, t7, t8, t9, pos=pos)

CONTAINS

Subroutine splits  (s, delim, t1, t2, t3, t4, t5, t6, t7, t8, sn, pos)
   implicit none
   Integer, Optional :: t1, t2, t3, t4, t5, t6, t7, t8, sn, pos
   Integer :: s,delim

   Call splits_str_to_str (s, delim, t1, t2, t3, t4, t5, t6, t7, t8, pos=pos)

End Subroutine


Subroutine splits_str_to_str  (s, delim, s1, s2, s3, s4, s5, s6, s7, s8, sn, pos)

     implicit none
     Integer, Optional :: s1, s2, s3, s4, s5, s6, s7, s8, sn, pos
     integer :: s,delim
     write(*,*)' In Splits_str_to_str',present(s1),present(s2),present(s3), &
               present(s4),present(s5),present(s6),present(s7),present(s8), &
               present(sn),present(pos)

End Subroutine

End Program

 

在原始文章中檢視解決方案

7 回應
mecej4
榮譽貢獻者 III
2,665 檢視

If you are confident that your subprogram code will reference optional arguments only if they are present, no, you need not check. If you have, say, three optional arguments and all three will be present if the first one is, it is sufficient to check only for the presence of the first. On the other hand, if you reference an optional argument that is not present, your program is almost sure to crash.

If you can organize your code such that the number of instances of IF(PRESENT())THEN...ENDIF are few, yet sufficient to ensure that no optional argument is referenced if not present, you would have reached a good compromise.

Vasili_M_
初學者
2,665 檢視

That means that I will be assuming some things, such as requirements of which optional arguments will be present?

mecej4
榮譽貢獻者 III
2,665 檢視

Correct. Essentially, you make an agreement with yourself as to which groups of optional arguments will be present during various calls. If this is either inconvenient or hard to adhere to, you can use IF (PRESENT...), but avoid putting that inside DO loops.

Vasili_M_
初學者
2,665 檢視
Would I be able to have the following code?

Program Test

  Call splits (s, delim, sn)
  Call splits (s, delim, sn, pos)
  Call splits (s, delim, t1, t2)
  Call splits (s, delim, t1, t2, pos)
  Call splits (s, delim, t1, t2, t3, t4, t5, t6, t7, t8, t9)
  Call splits (s, delim, t1, t2, t3, t4, t5, t6, t7, t8, t9, pos)

End Program


Subroutine splits  (s, delim, t1, t2, t3, t4, t5, t6, t7, t8, sn, pos)
   Integer, Optional :: s1, s2, s3, s4, s5, s6, s7, s8, sn, pos

   Call splits_str_to_str (s, delim, s1, s2, s3, s4, s5, s6, s7, s8, pos)

End Subroutine


Subroutine splits_str_to_str  (s, delim, s1, s2, s3, s4, s5, s6, s7, s8, sn, pos)

     Integer, Optional :: s1, s2, s3, s4, s5, s6, s7, s8, sn, pos

End Subroutine

 

mecej4
榮譽貢獻者 III
2,666 檢視

To the extent that optional arguments that may or may not be present can be passed along as actual arguments to other routines, yes. However, there are certain rules regarding optional arguments that your code does not satisfy. You have to provide explicit interfaces, and use the keyword=value form when arguments cannot be associated by position in the argument list.

Try the following fixed-up version. In the last call to "splits", "pos=pos" could be replaced by just "pos".

Program Test
  implicit none
  integer s, delim,sn,pos,t1,t2,t3,t4,t5,t6,t7,t8,t9

  Call splits (s, delim, sn=sn)
  Call splits (s, delim, sn=sn, pos=pos)
  Call splits (s, delim, t1, t2)
  Call splits (s, delim, t1, t2, pos=pos)
  Call splits (s, delim, t1, t2, t3, t4, t5, t6, t7, t8, t9)
  Call splits (s, delim, t1, t2, t3, t4, t5, t6, t7, t8, t9, pos=pos)

CONTAINS

Subroutine splits  (s, delim, t1, t2, t3, t4, t5, t6, t7, t8, sn, pos)
   implicit none
   Integer, Optional :: t1, t2, t3, t4, t5, t6, t7, t8, sn, pos
   Integer :: s,delim

   Call splits_str_to_str (s, delim, t1, t2, t3, t4, t5, t6, t7, t8, pos=pos)

End Subroutine


Subroutine splits_str_to_str  (s, delim, s1, s2, s3, s4, s5, s6, s7, s8, sn, pos)

     implicit none
     Integer, Optional :: s1, s2, s3, s4, s5, s6, s7, s8, sn, pos
     integer :: s,delim
     write(*,*)' In Splits_str_to_str',present(s1),present(s2),present(s3), &
               present(s4),present(s5),present(s6),present(s7),present(s8), &
               present(sn),present(pos)

End Subroutine

End Program

 

John_Campbell
新貢獻者 II
2,665 檢視

You should review your original logic as it presents some problems.
The second and subsequent if tests are only possible if t2 is NOT present, which implies that all your subsequent calls, which include t2 will fail.

If (Present (t2)) Then
  Call splits_str_to_int (s, delim, t1, t2)

Else If (Present (t3)) Then   
  Call splits_str_to_int (s, delim, t1, t2,t3)     !  Present (t2) = .false.

An alternative may be to provide a sufficiently large vector for ti's and a count of how many ti's are returned.
Isn't this count a function of the content of "s", rather than the supplied t1, t2,...

John

Vasili_M_
初學者
2,665 檢視

Yes you are right John

回覆