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>
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
連結已複製
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.
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.
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
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
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
