#fortran #overloading #fortran90
#fortran #перегрузка #fortran90
Вопрос:
Почему Fortran передает скалярное выражение в массив в выражении, но не в качестве аргумента процедуры? В частности, почему орган по стандартизации принял это проектное решение? Это исключительно из-за двусмысленности, должна ли процедура быть перегружена? Может ли сообщение об ошибке в этой ситуации быть альтернативным подходом?
Например, в приведенном ниже коде последнее утверждение x = foo(7)
выдает ошибку GFortran: Error: Rank mismatch in argument 'a' at (1) (1 and 0)
.
module m
public :: foo
contains
function foo(a) result(b)
integer, dimension(:) :: a
integer, dimension(size(a)) :: b
b = a 1
end function foo
end module m
program p
use m
integer, dimension(4) :: x
integer, parameter, dimension(4) :: y = (/1,2,3,4/)
x = 7
x = foo(x)
x = foo(y)
x = foo(x 7)
x = foo(7)
end program p
Этот вопрос должен был задавать вопрос о том, почему назначение массива приведет источник скалярного значения к целевому массиву; в отличие от функции массива. Я ожидаю, что это просто удобный частный случай. Любые комментарии, с благодарностью полученные в шапках ниже.
Ответ №1:
Если вы хотите, чтобы функция обрабатывала аргументы scaler и array, объявите ее как «элементарную» и с фиктивными аргументами scaler. Тогда он сможет обрабатывать как фактические аргументы scaler, так и массива, включая выражения scaler. Это удовлетворит ваши потребности?
Изменение:
elemental function foo(a) result(b)
integer, intent (in) :: a
integer :: b
b = a 1
end function foo
Возможно, они предоставили способ сделать то, что вы хотите, и одного способа было достаточно?
Комментарии:
1. Это, вероятно, не такое общее, как хочет OP, поскольку elemental накладывает множество ограничений на то, что может делать функция.
2. Да, конечно. Большинство встроенных функций являются элементарными, не так ли. И элементарной функции требуется arity > 1, чтобы таким образом продвинуть скаляр в массив. Мой вопрос был бы лучше сфокусирован на операторе присваивания, который будет продвигать скаляр. Но это имеет больше смысла: оператор присваивания является специальным. В последнее время я просматривал слишком много APL…
Ответ №2:
Вызов процедуры в Fortran с явными интерфейсами (которые вы получаете автоматически при использовании процедур модуля) требует соответствия TKR (тип, вид, ранг). Поскольку массив отличается от скалярного типа, не говоря уже о несоответствии ранга, это недопустимо.
Это из-за двусмысленности, должна ли процедура быть перегружена?
Это было бы проблемой, да.
Может ли сообщение об ошибке в этой ситуации быть альтернативным подходом?
Могут ли существовать розовые единороги? Возможно, но, насколько мне известно, они этого не делают. Итак, стандарт Fortran в настоящее время требует сопоставления TKR, и, следовательно, соответствующий стандарту компилятор должен обеспечить выполнение этого требования. Если вы хотите это изменить, я рекомендую внести предложение в комитет по стандартам.
Комментарии:
1. Спасибо janneb. Я ценю ваш ответ, но я на самом деле ищу «почему».
Ответ №3:
Я бы подумал, что ответ на это довольно ясен. Давайте немного изменим ваш пример:
module m
public :: foo
contains
function foo(a) result(b)
integer, dimension(:) :: a
integer, dimension(size(a)) :: b
b = a 1
a(2) = -777 ! new line; modify one element
end function foo
end module m
program p
use m
integer :: x
integer, dimension(4) :: y
x = 7
y = foo(x) ! pass a scalar
end program p
каким должен быть x после вызова foo?
Теперь, конечно, вы могли бы изменить семантику передачи аргументов в зависимости от того, является ли это intent(in)
переменной, но это не то, что прояснит ситуацию для программистов.
Если предполагается, что вызов функции каким-то образом «распределяется» по элементам массива, то, как указывает MSB, elemental — это правильный путь. В противном случае просто убедитесь, что ваши аргументы соответствуют вашим параметрам.
Комментарии:
1. Спасибо. Я думал, что аргумент будет
intent(in)
. Вот почему я включилparameter
аргумент,y
. Как вы говорите,elemental
это правильный путь.