2016-05-25 10 views
1

Ich habe einen abgeleiteten Typ V erstellt und eine Add-Funktion enthalten, so dass ich den Operator + verwenden kann.Fortran: Zugriff auf Werte vom Rückgabetyp einer Funktion

aber wenn ich

z = u + v 

die Operation nicht durchgeführt wird. Ich denke es ist, weil z%kn nicht zugegriffen wird.

aber wenn ich

Call vsum(z, u, v) 

alles

Nachfolgend finden Sie die Erklärung des abgeleiteten Typ und die Überlastung Funktion VADD erwartet funktioniert.

Module vtest 

Type :: V 

    Character (Len=8) :: kn 
    Real, Allocatable :: vc(:) 

    Contains 

    Procedure :: vadd 
    Generic :: Operator (+) => vadd 

End Type vtest 

Contains 

Function vadd (b, c) Result (a) 
    Type (V) :: a 
    Class (V), Intent (In) :: b, c 

    !!$ In vsum, use is made of a% kn 
    Call vsum (a, b, c) 

End Function vadd 

Subroutine vsum (ta, tb, tc) 
    Type (V), Intent (InOut) :: ta 
    Type (V), Intent (In) :: tb, tc 

    Logical :: la, lb, lc 

    la = .False.; lb = .False.; lc = .False. 

    Select Case (ta%kn) 

    Case ("Real32") 
    If (Allocated (ta%vc)) la = .True. 
    If (Allocated (tb%vc)) lb = .True. 
    If (Allocated (tc%vc)) lc = .True. 
    If (la .And. lb .And. lc) Then 
     ta%vc = tb%vc + tc%vc 
    End If 

    End Select 

End Subroutine vsum 

End Module vtest 


Program test 
Use vtest 
Type (V) :: z 

    z% kn = "Real32" 
    Allocate (z% vc_real32(3)) 
    Write (*,*) "z = u + v" 
    Write (*,*) "z% kn: ", z% kn 
    z = u + v 
    Write (*,*) "z% kn: ", z% kn 
    Write (*,*) "z: ", z% vc_real32 

End Program vtest 
+1

Bitte geben Sie Ihren Code für 'vsum' an. –

+0

Der Code ist immer noch unvollständig. Kaum ein mcve http://stackoverflow.com/help/mcve Es fehlt der Operator Aufruf und seine Umgebung. Es kann einen Fehler in jedem Detail geben, das Sie nicht gezeigt haben. Sie sollten einen vollständig kompilierbaren Code vorbereiten. Fügen Sie die Ausgabe Ihres Codes ein. Wie haben Sie festgestellt, dass die Operation nicht ausgeführt wird? Was ist stattdessen passiert? –

Antwort

2

Schauen wir uns das Unterprogramm vsum an. Die Arbeit, die in dieser Subroutine ausgeführt wird, hängt von der Definition der Komponenten aller drei Objekte ta, tb und tc ab. Damit Ihre Summierung so verläuft, wie Sie es erwarten, ist es notwendig, dass alle zuweisbaren Komponenten zugeordnet sind und für die Übereinstimmung von ta%kn mit 'Real32'.

Es gibt kein vollständiges Arbeitsbeispiel, aber wie Sie sagen, die Dinge funktionieren, wenn ein Anruf dort wie

ist
call vsum(z, u, w) ! V is the name of the type, so call the variable w 

z%kn auf 'Real32' gesetzt.

jedoch mit dem definierten Operation

z = u + w 

gibt die Referenz

Funktion ist
z = vadd(u, w) 

in dem der Anruf ist

call vsum (a, b, c) ! Actual arguments "z", u, w. 

Nun ist a das Funktionsergebnis von vadd. Dies hat zur Folge, dass ein Dummy-Argument mit intent(out)a zunächst undefiniert ist.

Das bedeutet im wesentlichen, wenn es durch vadd weitergegeben z macht es vsum mit undefinierter Komponente kn und nicht zugeordneten Komponente vc. Somit sind die Anforderungen für die Summierung nicht erfüllt (und die select case bildet tatsächlich eine ungültige Referenz).


Ich nehme an, ich kann kommentieren, wie man dieses Problem auch beheben kann.

In vsum nehmen Sie in der Tat die Art der Operation aus dem "Ergebnis". Stattdessen, so etwas wie

Subroutine vsum (ta, tb, tc) 
    Type (V), Intent (Out) :: ta 
    Type (V), Intent (In) :: tb, tc 

    Logical :: lb, lc 

    lb = .False.; lc = .False. 

    ! In here we probably want some consistency checking... 
    Select Case (tb%kn)  
    Case ("Real32") 
    If (Allocated (tb%vc)) lb = .True. 
    If (Allocated (tc%vc)) lc = .True. 
    If (lb .And. lc) Then 
     ta%vc = tb%vc + tc%vc ! ta%vc being automatically allocated 
    End If 
    End Select 

End Subroutine vsum 

Dies natürlich bezieht sie nicht auf Ihren scheinbaren Wunsch (aus dem Titel), um die Art der Operation aus dem Ergebnis zu nehmen.Sie könnte tun, dass mit Ihrem ursprünglichen Unterprogramm Ansatz, aber in einem Fall ist das nicht die Philosophie der Fortran-Funktionen.

Wenn Sie definierte Operationen verwenden möchten, kann die Operation nicht auf der linken Seite der Zuweisung definiert werden. In einem Ausdruck u+w gibt es keine linke Seite, aber es wird erwartet, dass sich die definierte Operation weiterhin verhält. Das ist auch zu sagen, in der Aussage

z = u + w 

Sie sagen nicht, „z das Ergebnis der Operation ist + angewendet u und w“. Aber: "die auf u und w angewendete Operation + wird ausgewertet und das Ergebnis (durch definierte oder implizite Zuweisung) z zugewiesen". Es gibt diese Zuordnung, bevor der "Typ des Ergebnisses" erreicht ist. Deshalb habe ich früher z als das eigentliche Argument in Anführungszeichen gesetzt.

+0

+1 Speziell für den letzten Absatz. Fortran-Funktionen "schauen" nie, was sich auf der linken Seite der Aufgabe befindet. Sie müssen überhaupt nicht in einer Aufgabe platziert werden! Sie berechnen einen Ausdruck und dieser Ausdruck wird dann irgendwie vom aufrufenden Code verwendet. –

+0

Das bedeutet, im Wesentlichen, wenn durch vadd z durchgeführt wird, macht es vsum mit undefinierte Komponente kn und nicht zugeordnete Komponente vc. Daher sind die Anforderungen für die Summierung nicht erfüllt (und der ausgewählte Fall bildet tatsächlich eine ungültige Referenz). --- Genau das passiert. – Zeus

+0

Haben Sie versucht, Ihre Änderung, aber ich bekomme immer noch nicht das Ergebnis korrekt zurückgegeben. Habe die Array-Werte nach dem Aufruf von 'vsum' in der Funktion 'vadd' ausgedruckt und bekomme die richtigen Werte. Im Hauptprogramm ist das ausgegebene Ergebnis jedoch immer noch undefiniert. – Zeus