unarios sobrecarga relacionales poo operadores operador matrices flujo oop fortran operator-overloading gfortran

oop - relacionales - sobrecarga de operador fortran(=)



sobrecarga del operador++ (3)

Para el operator(=) asignación definido operator(=) no es correcto, pero la assignment(=) es: ver Fortran 2008 12.4.3.4.3. Entonces, en cambio, quieres los dos bultos

public :: assignment (=)

y

interface assignment (=) module procedure vectorAssign end interface

Tenga en cuenta que la forma correcta de definir la asignación es mediante la subrutina tal como la tiene (aunque el asignatario podría tener la intent(out) lugar de la intent(inout) ).

¿Hay alguna forma de sobrecargar el operador = para que pueda escribir una tarea como en este ejemplo?

module constants_mod integer,parameter :: dpn = selected_real_kind(14) end module module vectorField_mod use constants_mod implicit none private public :: vectorField public :: allocateX,allocateY,allocateZ public :: delete ! public :: operator(=) type vectorField integer,dimension(3) :: sx,sy,sz real(dpn),dimension(:,:,:),allocatable :: x,y,z end type interface delete module procedure deallocateVectorField end interface ! interface operator (=) ! module procedure vectorAssign ! end interface contains ! function vectorAssign(f) result(q) ! implicit none ! real(dpn),intent(in) :: f ! type(vectorField) :: q ! q%x = f; q%y = f; q%z = f ! end function ! subroutine vectorAssign(f,g) ! implicit none ! type(vectorField),intent(inout) :: f ! real(dpn),intent(in) :: g ! f%x = g; f%y = g; f%z = g ! end subroutine subroutine allocateX(field,Nx,Ny,Nz) implicit none type(vectorField),intent(inout) :: field integer,intent(in) :: Nx,Ny,Nz if (allocated(field%x)) deallocate(field%x) allocate(field%x(Nx,Ny,Nz)) field%sx = shape(field%x) end subroutine subroutine allocateY(field,Nx,Ny,Nz) implicit none type(vectorField),intent(inout) :: field integer,intent(in) :: Nx,Ny,Nz if (allocated(field%y)) deallocate(field%y) allocate(field%y(Nx,Ny,Nz)) field%sy = shape(field%y) end subroutine subroutine allocateZ(field,Nx,Ny,Nz) implicit none type(vectorField),intent(inout) :: field integer,intent(in) :: Nx,Ny,Nz if (allocated(field%z)) deallocate(field%z) allocate(field%z(Nx,Ny,Nz)) field%sz = shape(field%z) end subroutine subroutine deallocateVectorField(field) implicit none type(vectorField),intent(inout) :: field deallocate(field%x,field%y,field%z) field%sx = 0; field%sy = 0; field%sz = 0 end subroutine end module program test use constants_mod use vectorField_mod implicit none type(vectorField) :: a integer :: N = 1 real(dpn) :: dt = 0.1 call allocateX(a,N,N,N) call allocateY(a,N,N,N) call allocateZ(a,N,N,N) a%x = dble(1.0) ! want to avoid this a%y = dble(1.0) ! want to avoid this a%z = dble(1.0) ! want to avoid this a = real(1.0,dpn) ! want this instead (does not compile) call delete(a) end program

He intentado de dos maneras diferentes (que se muestran en los comentarios) pero recibo errores que dicen que hay un error de sintaxis en la especificación genérica (para publicitar el operador =). ¡Cualquier ayuda para hacer esto es muy apreciada!


Sí, puede sobrecargar el operador de asignación. La sintaxis y los requisitos son diferentes para el operador de asignación que para otros operadores porque la semántica es fundamentalmente diferente: todos los demás operadores calculan un nuevo valor basado en uno o dos argumentos, sin cambiar los argumentos, mientras que la asignación cambia el valor de la mano izquierda argumento.

En tu caso, creo que debería verse así:

module vectorField_mod ! ... interface assignment (=) module procedure vectorAssign end interface contains ! ... subroutine vectorAssign(f,g) implicit none type(vectorField),intent(out) :: f real(kind = dpn), intent(in) :: g f%x = g f%y = g f%z = g end subroutine vectorAssign end module vectorField_mod


= no es un operador, es una misión en Fortran y son bestias muy diferentes.

Para la posibilidad clásica encontrada en Fortran 90 y explicada bien en otras respuestas, Fortran 2003 agregó una mejor posibilidad de vincular los operadores y asignaciones sobrecargados con el tipo derivado.

De esta forma, está seguro de que no importará el tipo sin la asignación (¡tenga cuidado con las declaraciones públicas y privadas en este caso!). Puede tener consecuencias muy desagradables y puede ser difícil de depurar:

type vectorField integer,dimension(3) :: sx,sy,sz real(dpn),dimension(:,:,:),allocatable :: x,y,z contains procedure :: assignVector generic :: assignment(=) => assignVector end type

De esta forma no tienes que ser tan cuidadoso como para no olvidarte de la public :: assignment (=)