В Аде контекст может определить, что «+» — это не строка, а целочисленный оператор, как в выражении: "+"(5,2)
. Вопрос в том, как мне сохранить этот оператор в переменной? Я хочу передать этот целочисленный оператор или какой-либо другой как бинарную функцию, принимающую два целых числа и возвращающую целое число. В приведенном ниже коде я сделал явную функцию, которая просто вызывает оператор, который я могу использовать в качестве обходного пути. Есть ли способ избежать этой оболочки и напрямую передать (доступ) оператору Integer «+»?
with Ada.Text_IO; use Ada.Text_IO;
procedure operator is
type binary_int_operator is access function(lhs : Integer; rhs : Integer) return Integer;
--plus : binary_int_operator := Integer."+"'Access;
--plus : binary_int_operator := Integer'Access("+");
--plus : binary_int_operator := Integer'"+";
--plus : binary_int_operator := "+";
function plus(lhs : Integer; rhs : Integer) return Integer is
begin
return lhs + rhs;
end plus;
begin
Put_Line(Integer'Image("+"(5, 12)));
end operator;
Закомментированные объявления показывают некоторые сделанные мной попытки, которые не компилируются.
Боюсь, вы не можете этого сделать. Подпрограмма "+"
для Integer
определена в пакете Standard
[АРМ А.1 (17)] и, следовательно, встроена [ААРМ А.1 (2.а)]. Не допускается ссылка на встроенную подпрограмму [АРМ 3.10.2 (32.3)]. Таким образом, компиляция программы
procedure Main is
type Binary_Int_Operator is
access function (lhs : Integer; rhs : Integer) return Integer;
Plus : Binary_Int_Operator := Standard."+"'Access;
begin
null;
end Main;
урожаи
6:34 prefix of "Access" attribute cannot be intrinsic
Единственный обходной путь — использование косвенного обращения. Эта программа компилирует
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
procedure Main_Alt is
type Operation is
access function (Lhs, Rhs : Integer) return Integer;
-- Sticking to "+" and "-" instead of names like Add or Subtract
-- to demonstrate that you can reference operator subprograms
-- (using the Access attribute) as long as they're not intrinsic.
function "+" (Lhs, Rhs : Integer) return Integer is
(Standard."+" (Lhs, Rhs));
function "-" (Lhs, Rhs : Integer) return Integer is
(Standard."-" (Lhs, Rhs));
procedure Calc_And_Show (Lhs, Rhs : Integer; Op : Operation) is
begin
Put (Op (lhs, rhs));
New_Line;
end Calc_And_Show;
begin
Calc_And_Show (5, 3, "+"'Access);
Calc_And_Show (5, 3, "-"'Access);
end Main_Alt;
и урожаи (как и ожидалось)
$ ./main_alt
8
2
Я бы предложил рассмотреть другой подход с использованием дженериков. Как правило, я думаю, что вы получаете более простой интерфейс для звонка, чем вы get пытается передать доступ к параметрам подпрограммы. (т.е. не нужно передавать операцию для каждого вызова).
Используя дженерики, вам вообще не нужно использовать «Доступ», и вы могу передаете встроенные функции, такие как целое число «+», в качестве формальных универсальных параметров.
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
procedure Main is
generic
with function Op (L, R : Integer) return Integer;
procedure Calc_And_Show (Lhs, Rhs : Integer);
procedure Calc_And_Show (Lhs, Rhs : Integer) is
begin
Put (Op (lhs, rhs));
New_Line;
end Calc_And_Show;
procedure Calc_And_Show_Plus is new Calc_And_Show (Op => "+");
procedure Calc_And_Show_Minus is new Calc_And_Show (Op => "-");
begin
Calc_And_Show_Plus (5, 3);
Calc_And_Show_Minus (5, 3);
end Main;
Могут быть причины, по которым вы захотите использовать вместо этого параметры доступа, например, если вы хотите, чтобы Calc_And_Show можно было вызывать из других языков, таких как C, или если вы находитесь на вложенном уровне кода и все, что вы передали на свой вложенный уровень является доступом к значению подпрограммы. Но я думаю, что в целом рекомендуется использовать дженерики или, по крайней мере, рассматривать этот вариант в качестве первого предпочтения, если у вас нет веских причин не делать этого.
Аккуратный ответ, показывающий дженерики Ады. К сожалению, в этом случае это действительно не отвечает на вопрос, как и другой ответ: «нет, вы не можете». В моем случае мне нужно выбрать операцию во время выполнения, поэтому даже с этими универсальными функциями между ними мне понадобится оператор case, который передает полностью указанные универсальные функции, поэтому мне все равно нужно будет передать доступ к функции.
Да, я тоже пробовал :-), но переименование подпрограммы, в конце концов, просто получение представления об исходной подпрограмме. Все свойства (включая внутреннее соглашение о вызовах) наследуются [ARM 8.5.4(7)].