2016-09-22 43 views
6

Ja próbuje przejść procedurę ogólną jako rzeczywisty argument do funkcji:Podjęcie procedury rodzajowe do funkcji jako argumentu rzeczywistego

module mymod 
implicit none 

interface func 
    module procedure :: func1 
    module procedure :: func2 
endinterface func 

contains 

real function func1(x) 
    real,intent(in) :: x 
    func1 = 2*x 
endfunction func1 

real function func2(x,y) 
    real,intent(in) :: x 
    real,intent(in) :: y 
    func2 = 2*x + 3*y 
endfunction func2 

real function func3(func,x,y) 
    interface 
    real function func(x,y) 
     real,intent(in) :: x 
     real,intent(in) :: y 
    endfunction func 
    endinterface 
    real,intent(in) :: x 
    real,intent(in) :: y 
    func3 = func(x,y) 
endfunction func3 

endmodule mymod 

program myprogram 
use mymod 
implicit none 
write(*,*)func3(func,2.,3.) 
endprogram myprogram 

gfortran 6.2.0 zauważa, że ​​nie mogę tego zrobić:

test.f90:43:16: 

write(*,*)func3(func,2.,3.) 
       1 
Error: GENERIC procedure ‘func’ is not allowed as an actual argument at (1) 

Podobnie z ifort 17:

test.f90(39): error #8164: A generic interface name shall not be used as an actual argument. [FUNC] 
write(*,*)func3(func,2.,3.) 
----------------^ 
test.f90(39): error #6637: When a dummy argument is a function, the corresponding actual argument must also be a function. [FUNC] 
write(*,*)func3(func,2.,3.) 
----------------^ 
compilation aborted for test.f90 (code 1) 

czytam pośrednictwem standardowej sekcji dotyczącej genu 2008 interfejsy ric i nie mogę znaleźć takiego ograniczenia. Nie mogę też wymyślić przyczyny, dla której kompilator nie byłby w stanie rozwiązać ogólnego interfejsu podczas kompilacji. Moje jelit mówi mi, że powinno to być wykonalne, ale może nie mam właściwego podejścia. Czy znasz standardową metodę, aby to zrobić?

Odpowiedz

5

Nie, jest to niedozwolone. W rzeczywistości nie można nawet przekazać ogólnych funkcji INTRINSIC jako fałszywych argumentów.

Standardowo zgodny sposób polega na bezpośrednim użyciu właściwych konkretnych funkcji. Dzięki funkcjom INTRINSIC czasem trzeba napisać wrapper dla właściwego rodzaju, gdy specyfikacja nie ma standardowej nazwy.

Na przykład:

call integrate(derf,0.,1.) 

    contains 
    function derf(x) 
     real(dbl) :: derf 
     real(dbl), intent(in) :: x 
     derf = erf(x) 
    end function 
    end 

jest konieczne, jeśli chcesz zdać podwójnej precyzji rzeczywistym (lub jakiegokolwiek innego) wersję erf() ponieważ nie ma specyficzna funkcja jest dostępna.

+1

zawsze jasne i do tego stopnia, dzięki. – milancurcic

+6

Będę komentować, że użycie określonych funkcji stanie się niestandardowe w Fortran 2015. W tym momencie nie będzie sposobu przekazania funkcji wewnętrznej jako argumentu procedury i będzie musiał użyć metody opakowania, aby zachować zgodność ze standardami. (Zwracam również uwagę, że od Fortran 95 nie dodano żadnych nowych nazw konkretnych dla właściwości wewnętrznych). –

1

Standard Fortran nie zezwala na przekazywanie ogólnych procedur jako argumentów. Aby móc przekazywać wewnętrzne funkcje/podprogramy, należy odwoływać się do zdefiniowanych przez użytkownika procedur otoki.

module mymod 

    ! Explicit typing only 
    implicit none 

    ! Declare procedure interface 
    interface 
     function my_func(x, y) result (return_value) 
     real, intent(in) :: x, y 
     real    :: return_value 
     end function my_func 
    end interface 

contains 

    function func1(x) result (return_value) 
     real,intent(in) :: x 
     real   :: return_value 

     return_value = 2*x 

    end function func1 

    function func2(x, y) result (return_value) 
     real, intent(in) :: x, y 
     real    :: return_value 

     return_value = 2*x + 3*y 

    end function func2 

    function func3(user_defined_func, x, y) result (return_value) 
     procedure(my_func) :: user_defined_func 
     real, intent(in) :: x, y 
     real    :: return_value 

     return_value = user_defined_func(x,y) 

    end function func3 

end module mymod 

program main 

    use ISO_Fortran_env, only: & 
     stdout => OUTPUT_UNIT, & 
     compiler_version, & 
     compiler_options 

    use mymod 

    ! Explicit typing only 
    implicit none 

    write (stdout, *) func3(func2, 2.0, 3.0) 
    write (stdout, *) func3(foo, 2.0, 3.0) 
    write (stdout, *) func3(my_atan2, 2.0, 3.0) 

    print '(/4a/)', & 
    ' This file was compiled using ', compiler_version(), & 
    ' using the options ', compiler_options() 

contains 

    ! A user defined function 
    function foo(x, y) result (return_value) 
     real, intent(in) :: x, y 
     real    :: return_value 

     return_value = 42 

    end function foo 

    ! A wrapper function to invoke the intrinsic atan2 
    function my_atan2(x, y) result (return_value) 
     real, intent(in) :: x, y 
     real    :: return_value 

     return_value = atan2(x,y) 

    end function my_atan2 

end program main 

daje

gfortran -std=f2008ts -o main.exe mymod.f90 main.f90 
./main.exe 
    13.0000000  
    42.0000000  
    0.588002622  

This file was compiled using GCC version 6.1.1 20160802 using the options -mtune=generic -march=x86-64 -std=f2008ts