«Недопустимая операция» при перегрузке дополнения для производного типа с использованием ifort - PullRequest
0 голосов
/ 03 октября 2018

Это дополнительный вопрос из темы, которую я начал здесь здесь.

По сути, я хочу добиться определения отложенного типа, который автоматически назначает примитивные типы (действительное, целое, символьное и логическое). Вы можете увидеть рабочий пример при переходе по вышеуказанной ссылке, и он компилируется с gcc version 7.3.0 и ifort version 18.0.0.

Я теперь расширил код вДля того, чтобы «использовать» отложенный тип данных, не зная, какой тип примитива назначен.Это работает путем переопределения основных операторов.Для простоты я включил только оператор + в следующем примере.Пример работает и компилируется с gfortran , но выдает ошибку при компиляции с ifort :

Ошибка # 6303: Операция присваивания или двоичное выражениеоперация недопустима для типов данных двух операндов.[PLUS_FUNC_CLASS] c% i = a% i + b% i

Кто-нибудь знает, в чем здесь проблема?Я уже погуглил ошибку, но не смог выяснить, что я делаю неправильно.


NOTE

, чтобы соответствовать точности, я использовал следующую компиляцию флаги

ifort -r8 -i8 tst.f90

gfortran -fdefault-real-8 -fdefault-integer-8 -fdefault-double-8 tst.f90


Вот пример кода:

module DervType

  implicit none

  type, public :: mytype
    real                          :: r
    integer                       :: i
    character(len=:), allocatable :: c
    logical                       :: l
  end type

  interface assignment(=)
    module procedure equal_func_class
  end interface

  interface operator(+)
    module procedure plus_func_class
  end interface

contains

   subroutine equal_func_class(a,b)
        type(mytype), intent(out):: a
        class(*),     intent(in) :: b

        select type (b)
            type is (mytype)
                print *, "is mytype"
                if ( .not. a%r == b%r ) a%r = b%r      !! <-- ugly, but necessary not to end up in an endless loop when reassigning mytype (only testing and assigning real here)
            type is (real)
                print *, "is real"
                a%r = b
            type is (integer)
                print *, "is int"
                a%i = b
            type is (character(len=*))
                print *, "is char"
                a%c = b
            type is (logical)
                print *, "is logical"
                a%l = b 
        end select

    return

  end subroutine equal_func_class


  recursive function plus_func_class(a,b) result(c)
        class(*), intent(in)        :: a
        class(*), intent(in)        :: b
        type(mytype)                :: c

        select type (a)
            type is (mytype)
                print *, "left side is mytype"

                !! -------------------------------
                !! only testing one case here and only real operations are
                !! taken care of!
                !! -------------------------------
                select type (b)
                    type is (mytype)
                        print *, "right side is mytype"                       
                        c%i = a%i + b%i  !! <-- this is where ifort throws the error
                        c%r = a%r + b%r  !! <-- this is where ifort throws the error 
                    type is (real)
                        print *, "right side is real", a%r
                        c = a%r + b
                end select

            !! do similar logic when the operands changing sides
            type is (real)
                print *, "left side is real"
        end select

        !c = 1.

        return        

    end function plus_func_class


end module DervType

program TestType

  use DervType

  implicit none

  type(mytype) :: test, test2, res, res2

  real, parameter :: tt = 2.

  test = 1.
  test = 1
  test = "Hey Tapir"
  test = .true.

  test2 = 2.

  test = test2

  print *, "test = ", test%r

  res  = test + 1.0
  res2 = test + tt

  print *, "Calculation 1 (real) : ", res%r
  print *, "Calculation 2 (real) : ", res2%r

end program TestType

При компиляции с gfortran и при запуске программы это дает следующий вывод:

 is real
 is int
 is char
 is logical
 is real
 is mytype
 test =    2.0000000000000000     
 left side is mytype
 right side is real   2.0000000000000000     
 is real
 is mytype
 left side is mytype
 right side is real   2.0000000000000000     
 is real
 is mytype
 Calculation 1 (real) :    3.0000000000000000     
 Calculation 2 (real) :    4.0000000000000000 

1 Ответ

0 голосов
/ 03 октября 2018

Давайте сократим этот пример программы до чего-то более управляемого:

 module DervType

  implicit none

  type mytype
    integer i
  end type mytype

  interface operator(+)
    module procedure plus_func_class
  end interface

contains

  recursive function plus_func_class(a,b) result(c)
    class(*), intent(in)        :: a
    class(*), intent(in)        :: b
    type(mytype)                :: c

    c%i = 1+1
  end function plus_func_class

end module DervType

ifort 18.0.3 для меня жалуется на это:

error #6303: The assignment operation or the binary expression operation is invalid for the data types of the two operands.   [PLUS_FUNC_CLASS]
    c%i = 1+1
-----------^

Знакомый?

Что ж, похоже, потому что у нас есть аргументы plus_func_class, поскольку неограниченный полиморфный ifort решает использовать эту функцию в качестве специальной процедуры для универсального operator(+) с выражением 1+1.(Удалите префикс recursive, чтобы увидеть больше.)

Мы не хотим, чтобы это делалось.Можем ли мы убедить его не делать этого?

Мы хотим, чтобы наша истинная функция учитывала случаи, когда левая или правая стороны имеют значение class(mytype), поскольку нам не нужно переопределять intrinsic+intrinsic.Я не буду выписывать детали, но вы можете реализовать эту функцию дважды: один раз с LHS class(mytype) и RHS class(*) и один раз с LHS class(*) и RHS class(mytype).


Даже если человек изначально рассматривает этот подход просто как «обходной путь ошибки компилятора», действительно стоит реализовать определенную операцию без использования неограниченных полиморфных аргументов для обеих сторон операции сложения

Когда вы хотите создать новыйвведите mytype2, вы не хотите определять операцию с помощью функции plus_func_class.Хотя вам это понадобится, потому что у вас будет неоднозначный интерфейс, если вы создадите новую специальную функцию для универсального operator(+).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...