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 (=)