РЕДАКТИРОВАТЬ, чтобы предоставить более подробную информацию:
1) Код, предоставляющий библиотеки, нельзя (легко) изменить, поэтому profile_v1_type
и profile_v2_type
следует считать неизменяемыми.
Я реализовал предложение @francescalus, и оно работает для моего небольшого тестового примера, но я думаю, что недостаточно ясно понял проблему. Причина в том, что я могу изменять только свой код, а не код/типы, поступающие из библиотеки. Проблема будет заключаться в том, что оба будут иметь t
в импортированном profile_type, который конфликтует с родительским типом.
Но я собираюсь реализовать что-то, где я реплицирую содержимое производного типа, который мне нужен, а затем использую указатели и процедуры, связанные с типом, чтобы указать на компоненты версии profile_type, которые я хочу использовать. Здесь не так чисто, как хотелось бы, но намного лучше, чем сейчас.
Я поддерживаю код, который взаимодействует с другим, который имеет 2 версии - две версии очень похожи по интерфейсу, и хотя входы и выходы идентичны по свойствам, они, очевидно, являются разными производными типами (они происходят из разных библиотек и немного отличаются в переменные, содержащиеся внутри. Большинство имен переменных внутри этих типов одинаковы, хотя и принципиально).
(Очевидно) необходимо поддерживать оба во время выполнения, иначе я бы предварительно обработал все это во время компиляции.
На данный момент я лениво скопировал и вставил один и тот же код для каждой версии (и всех версий используемых производных типов) в отдельные подпрограммы (*_v1.f90, *_v2.f90).
Это раздражает и не очень ремонтопригодно.
Что я хотел бы сделать, так это использовать какой-то указатель, который не заботится о том, на что он указывает (или, скорее, получает информацию о своем типе из того, на что он указывает, и достаточно умен, чтобы знать, что внутри).
Как я уже сказал выше, имена в основном одинаковы, например. (t, для температуры, скажем)
Из v1 библиотеки:
TYPE profile_v1_type
REAL :: t
! loads of other stuff
END TYPE profile_v1_type
Из v2 библиотеки:
TYPE profile_v2_type
REAL :: t
! loads of other stuff, more than the first version
END TYPE profile_v2_type
В моем коде:
TYPE profile_container_type
TYPE(profile_v1_type) :: profile_v1
TYPE(profile_v2_type) :: profile_v2
! other arrays that are common inputs to both
END TYPE
! It's actually USE'd then allocated and initialised elsewhere, but I hope you get the idea
!USE profile_container_mod, ONLY : profile_container
TYPE(profile_container_type), TARGET :: profile_container
TYPE(*) :: p
REAL :: t1
!Version determined by a namelist
IF (Version == 1) THEN
p => profile_container % profile_v1
ELSE IF (Version == 2) THEN
p => profile_container % profile_v2
ENDIF
t1 = p % t + 1
.
.
.
ifort 19 выдает эти (ожидаемые) ошибки:
test.f90(24): error #8776: An assumed type object must be a DUMMY argument. [P]
TYPE(*), POINTER :: p
--------------------^
test.f90(24): error #8772: An assumed type object must not have the ALLOCATABLE, CODIMENSION, POINTER, INTENT(OUT) or VALUE attribute. [P]
TYPE(*), POINTER :: p
--------------------^
test.f90(39): error #6460: This is not a field name that is defined in the encompassing structure. [T]
t1 = p % t + 1
---------^
compilation aborted for test.f90 (code 1)
заменить TYPE(*) на CLASS(*) дает (все еще ожидается):
test2.f90(39): error #6460: This is not a field name that is defined in the encompassing structure. [T]
t1 = p % t + 1 ! or some clever function...
---------^
compilation aborted for test2.f90 (code 1)
Это можно исправить, выбрав тип, который вы хотите обработать, но я хочу сделать одно и то же для кода v1 и v2 (никогда не будет одновременно). И я хочу сделать это много раз, не в этом упражнении, а примерно в дюжине упражнений.
Я открыт для использования указателей C, если ответчик может предоставить простой пример для подражания. Я пытался (не недавно) решить эту проблему, используя совместимость C, но, очевидно, безуспешно!