2014-11-27 3 views
2

class(*) 기능으로 유용한 배열 연산 (요소 추가, 요소 제거, 다른 구현을 할당 가능/포인터/이진 트리 구조)을 실현하고 싶습니다. (무제한 다형성). 그런 기능을 처리해야하는 gfortran 5.0을 사용합니다. 내가 사용하는 각 유형에 대해 동일한 코드를 반복하지 않기를 원합니다.Fortran 03/08 (gfortran 컴파일러)에서 배열 연산에 무제한 다형성 유형 사용

이 문제는 좀 명확한 유형이 기능을 사용하려고 할 때, 나는 결과를 반환에 오류가 있다는 것입니다

function add_element(array,element) 
    class(*),intent(in)::array(:) 
    class(*),intent(in)::element 
    class(*)::add_element(size(array)+1) 
     add_element=[array,element] 
end function 

처럼 보일 것이다. 나는 select type없이 어떤 확실한 타입 변수에 class(*)을 할당 할 수 없으며, 사용할 때마다 타입 구조를 선택하고 싶지는 않습니다. 서브 루틴 안에는 내가 사용하고자하는 타입에 관해서는 알지 못한다. 왜냐하면 내가 그것들을 많이 만들 것이기 ​​때문이다.

move_alloc 소스와 함께 변종을 시도했는데 intent(out) 인수 등으로 서브 루틴을 사용해 보았습니다. 작동하지 않았습니다. 나는 그것이 인수 속성에서 정의되어야한다고 생각한다. (크기는 소스 키워드로?) 표준에서 그러한 구조의 예제 나 정의를 찾지 못했다. 물론이 표준을 더 공부할 것입니다. (저는 프로 프로그래머가 아니지만 물리학 자들이 내 프로그램을 테스트 할 수 있고, 확인 가능하며, 변경하기가 쉽도록하려고 노력합니다.) 더 나은 솔루션을 기다리면서이 코드를 반복 할 것입니다. 표준 또는 일부 책에서 검색하려면? 배열에 대해서만이 아니라 class(*)을 사용하는 것이 좋습니다. 형식을 모르는 메서드가 있어야한다고 생각하기 때문에 ...

다른 형식의 예제를 추가해야하는지 모르겠습니까? 이 서브 루틴 또는 오류에 대한 내용 - 또는 질문에 초점이 맞지 않습니다. 그것은 컴파일 될 수 있지만, 모든 경우에 호출에서 명확한 유형에 할당이 작동하지 않습니다. 인수 intent(out) 또는 (inout)의 경우에는 가상 인수에서 실제 인수로 이동할 수 없습니다. 소스에서 재 할당하면 유형이있는 객체가 만들어 지지만 형식이 숨겨져 있습니다. 유형을 모르기 때문에 서브 루틴에서 select 유형을 사용할 수 없습니다. 또한

내가 "와 같은 유형"을 확인하거나 이런 맥락에서 뭔가 수있는 구조를 모르는 ...

답변

3

이 당신은 select type를 사용할 수있는 쉬운 문제가되지 않지만 포트란 아무것도 없습니다 type is(type_of(x))입니다. 반면에 SAME_TYPE_AS()EXTENDS TYPE_OF() 내장 프로그램이 있지만 형식 가드로 사용할 수 없습니다.

arrayelement의 동적 유형이 동일해야합니다.

나는 이것이 표준의 결핍이라고 생각한다.

하지만 여전히 방법에 오류가 있습니다. 당신은 함수 결과 할당 가능한을해야 동적 유형의 수정을 할당 할 수 있도록 :

class(*), allocatable ::add_element(:)

당신의 라인을 따라 뭔가 생각 :

(! 안된이 gfortran-4.9 ifort14로 컴파일을)

allocate(add_element(size(array)+1), mold=array)

하지만 실제로 전달할 값을 전송하는 방법 및 일부 더러운 속임수를 사용하지 않고 가능하지 않을 수도 있습니다 걱정입니다.

transfer을 사용할 수 없으며 이것이 실제 결함이있는 부분입니다. 당신이 다형성 금형과 전송을 호출 할 수 있습니다 그겁니다

transfer(element, add_element(1)) 

당신은

add_element(1) = transfer(element, add_element(1)) 

내 의견 포트란은 두를 보장 유형 가드에 대한 옵션을 부족이다 배열 요소에 할당 할 수있는 방법이 없습니다 변수에는 동일한 동적 유형이 있습니다. (! 안된 gfortran-4.9 ifort14로 컴파일) :

는 당신의 라인을 따라 뭔가를 생각

function add_element(array,element) 
    use iso_c_binding 
    implicit none 
    class(*),intent(in)::array(:) 
    class(*),intent(in)::element 
    class(*), allocatable ::add_element(:) 
    type(c_ptr) :: tmp 

    interface 
    function memcpy(dest, src, n) bind(c) 
     use iso_c_binding 
     integer(c_intptr_t),value :: dest, src 
     integer(c_size_t) :: n 
     type(c_ptr) :: memcpy 
    end function 
    end interface 

    allocate(add_element(size(array)+1), mold=array) 

    tmp = memcpy(loc(add_element(size(array)+1)), & 
       loc(array), & 
       size(array, kind=c_size_t) * storage_size(array, c_size_t)/8_c_size_t) 
    tmp = memcpy(loc(add_element(size(array)+1)), & 
       loc(array(1)), & 
       storage_size(element, c_size_t)/8_c_size_t) 

end function 
+0

답변 해 주셔서 감사합니다. 나는 그것이 표준 문제라고 생각했다. 그러나 새로운 표준 버전을 기다리는 것은 클래스 (*)를 전혀 사용하지 않는 것과 같다. 결과를 반환하지 않고 어떻게 사용할 수 있는지 모르겠다. –

+0

Fortran에서 클래스 (*)를 반환 할 수 있습니다! 문제는 값을 설정하는 것입니다. –

+0

할당을 사용하여 변형을 시도했습니다. 단순함을 위해 그리고 배열 크기를 검사하기를 선호하기 때문에 - 보통과 같은 구조가 가능합니다. 그러나 할당 이동 할당 할 수 있습니다 동일한 반환 ...
물론 내가 인수 형식을 확인하는 것이 좋습니다하지만 어떻게 해야할지 모르겠다, 나는 same_type_as 기억하지만 내가 원하는 것을 반환 할 수 없습니다.
당신의 예제와 C 바인딩을 사용하는 표준 부분에 대해서는 C를 모르지만 (필자는 필연적으로 그것을 지연했다 ...) 나는 그것을 고맙게 생각한다. –

2

CLASS (*) 기본적으로 실행시의 형태 안전하지만, 형 무관 저장 할 수있는 기능입니다. 컴파일 타임 타입 매개 변수화 메커니즘으로 사용하려고합니다. 그것은 대단히 적절하지 않으며, 언어는 대체 수단을 직접적으로 지원하지 않습니다.

전통적으로 유형화 매개 변수화는 매개 변수화 할 프로 시저의 공통 부분을 별도의 파일에 배치 한 다음 암시 적 유형 지정을 사용하여 매개 변수화 할 유형을 지정하는 모듈에 적절하게 해당 파일을 포함시킴으로써 수행됩니다.

CLASS (*)를 사용해야하는 경우 실질적으로 래퍼 유형을 작성하고 사용해야합니다. 랩핑을 모두 기본 배열 조작이라면, 이것은 가치가있는 것보다 훨씬 더 어려울 것입니다.

저장되어있는 것을 추출하는 클라이언트 코드 (일반적인 절차와 비교)에서 일반적으로 SELECT TYPE을 사용해야합니다 (데이터 유형에 BIND (C) 또는 SEQUENCE가있는 경우 포인터 할당을 사용할 수 있지만이 경우 유형 안전하지 않음).

TYPE :: Wrapper 
    CLASS(*), ALLOCATABLE :: item 
END TYPE Wrapper 

FUNCTION add_element(array, element) 
    TYPE(Wrapper), INTENT(IN) :: array(:) 
    CLASS(*), INTENT(IN) :: element 
    TYPE(Wrapper), INTENT(OUT) :: add_element(SIZE(array)+1) 
    ! If you want to enforce type consistency (at runtime)... 
    IF (SIZE(array) > 0) THEN 
    IF (.NOT. SAME_TYPE_AS(array(1)%item, element)) THEN 
     STOP 'Objects not of same type!' 
    END IF 
    END IF 
    add_element(:SIZE(array)) = array 
    add_element(SIZE(add_element))%item = element 
END FUNCTION add_element 

FUNCTION get(scalar) 
    TYPE(Wrapper), INTENT(IN) :: scalar 
    CLASS(*), ALLOCATABLE :: get 
    get = scalar%item 
END FUNCTION get 

... 

TYPE(Wrapper), ALLOCATABLE :: array(:) 
array = [ Wrapper :: ] 
array = add_element(array, 'cat') 
array = add_element(array, 'dog') 

DO i = 1, SIZE(array) 
    SELECT TYPE (item => get(array(i))) 
    TYPE IS (CHARACTER(*)) 
    PRINT "(A)", item 
    END SELECT 
END DO 
+0

나는 그가 파라 메트릭 다형성을 시도한다고 말하지 않을 것이다. 나에게 그것은 C의 고전적인 타입없는 다형성 (memcpy와 다른 많은 일반적인 함수들에서와 같이)과 더 유사하게 보인다. 당신이 제안하는 것은 그가하는 것과는 정반대의 것입니다. 그는 정상적인 데이터를 가지고 있으며 그에 대응하기위한 일반적인 절차에 대처하려고합니다. 이 문제에 도움이되지 않는 새로운 데이터 유형을 만듭니다 (예 : 정수 배열 또는 실제 배열 또는 일부 유형 (x)에 요소 추가). –

+2

나는 그것을 명확히하기 위해 영업점에 맡긴다. 그러나 다른 유형에 대해 "동일한 코드 반복"에 관한 질문에 언급이있다. 일반 프로그래밍 (매개 변수화 유형 또는 매개 변수 다형성 또는 사용하고자하는 용어)의 필요성에 대한 합당한 징후입니다.'CLASS (*)'는 일반적인 저장소/참조 기능을 제공하지만 일반 작업을위한 기능은 제공하지 않습니다. 'CLASS (*)'를 사용하고 일반적인 연산을 캡슐화하려면 실제로 래퍼 유형이 필요합니다. 대안은 INCLUDE/IMPLICIT 트릭을 사용하는 것입니다. Fortran 95에서는 memcpy/TRANSFER를 사용할 수 있지만 F2003에서는 사용할 수 없습니다! – IanH