Вложенный производный тип с перегруженным назначением

У меня есть производный тип (wrapper) содержащий другой производный тип (over). Для последнего оператор присваивания был перегружен. Поскольку присвоение производных типов происходит по умолчанию по компонентам, я ожидаю, что назначение двух экземпляров wrapper будет вызывать перегруженное назначение для over в какой-то момент. Однако, используя программу ниже, это не похоже на случай. Перегруженное назначение вызывается только в том случае, если я также перегружаю назначение для wrapper содержащий явное присваивание между экземплярами over (раскомментируя закомментированные строки кода). Зачем? Я нахожу это несколько противоречивым. Есть ли способ избежать перегрузки в типе упаковки?

module test_module
  implicit none

  type :: over
    integer :: ii = 0
  end type over

  type :: wrapper
    type(over) :: myover
  end type wrapper

  interface assignment(=)
    module procedure over_assign
    !module procedure wrapper_assign
  end interface assignment(=)

contains

  subroutine over_assign(other, self)
    type(over), intent(out) :: other
    type(over), intent(in) :: self

    print *, "Assignment of over called"
    other%ii = -1

  end subroutine over_assign

  !subroutine wrapper_assign(other, self)
  !  type(wrapper), intent(out) :: other
  !  type(wrapper), intent(in) :: self
  !
  !  other%myover = self%myover
  !
  !end subroutine wrapper_assign

end module test_module

program test
  use test_module
  implicit none

  type(wrapper) :: w1, w2

  print *, "Assigning wrapper instances:"
  w2 = w1

end program test

2 ответа

Решение

Эта [неудачная] ситуация является следствием правил языка (F90+) для внутреннего присваивания производных типов. Детали изложены в F2008 7.2.1p13. Таким образом, внутреннее присваивание производных типов (присваивание, которое происходит с закомментированным конкретным атрибутом wrapper_assign) не вызывает присвоения, не связанного с типом, для любых компонентов производного типа. В F90/F95, если вы хотите определить назначение на каком-то более низком уровне иерархии компонентов, вам необходимо определить назначение для всех родительских компонентов вплоть до базового объекта.

F2003 добавило определенное присвоение языку с привязкой к типу, и это вызывается внутренним присваиванием производных типов. Используйте это вместо автономной универсальной формы указания определенного назначения. (Это также позволяет избежать потенциальной проблемы с доступностью имени типа, но недоступна определенная процедура присваивания.)

Просто чтобы завершить тему: конкретная реализация предложения IanH (пожалуйста, опишите его первоначальный ответ, а не этот), который работал для меня, была следующей:

module test_module
  implicit none

  type :: over
    integer :: ii = 0
  contains
    procedure :: over_assign
    generic :: assignment(=) => over_assign
  end type over

  type :: wrapper
    type(over) :: myover
  end type wrapper

contains

  subroutine over_assign(other, self)
    class(over), intent(out) :: other
    class(over), intent(in) :: self

    print *, "Assignment of over called"
    other%ii = -1

  end subroutine over_assign

end module test_module


program test
  use test_module
  implicit none

  type(wrapper) :: w1, w2

  print *, "Assigning wrapper instances:"
  w2 = w1

end program test
Другие вопросы по тегам