Невозможно получить доступ к элементам универсального параметра Ada - PullRequest
5 голосов
/ 26 февраля 2010

Я пытаюсь написать универсальный пакет, и одна из необходимых операций - проверка контрольных сумм записей данных, полученных по шине. Тип записи будет отличаться, и это общий параметр. Однако любые попытки получить доступ к элементам универсального параметра вызывают ошибку компиляции.

Ошибка ... (Ада 95 GNAT 2009)

file.adb:XX no selector "Data" for private type "The_Transfer_Type" defined at file.ads:YY

Декларация ...

generic
  type The_Transfer_Type is private;
  SIZE : Integer;
package CC_Test_Channel is
  function Checksum(Msg : The_Transfer_Type) return Integer;
end package

И тело ...

function Checksum(Msg : The_Transfer_Type) return Integer is
  Sum : Integer := 0;
begin
  -- calculate the checksum
  for i in 1 .. SIZE loop
    Sum := Sum + Integer(Msg.Data(i));
  end loop;
  return Sum;
end Checksum;

Ответы [ 3 ]

5 голосов
/ 26 февраля 2010

Когда вы указываете, что универсальный параметр является закрытым типом, Ада предполагает, что вы это имеете в виду: -)

т.е. у вас нет доступа к его компонентам. Ада не является " типом утки ", поэтому не имеет значения, знаете ли вы, что экземплярный тип может действительно обладать определенным полем. (Как вы ожидаете, что ваша функция Checksum будет работать, если параметр The_Transfer_Type был создан, например, с помощью Integer?)

Одним из способов решения этой проблемы является также предоставление функции доступа в качестве параметра для универсального объекта, который будет извлекать данные, необходимые, в данном случае, для вычисления контрольной суммы. E.g.:

generic
   type The_Transfer_Type is private;
   with function Get_Checksummable_Data_Item
           (Msg : The_Transfer_Type;
            I   : Integer) return Integer;
   SIZE : Integer;

package CC_Test_Channel is
   function Checksum(Msg : The_Transfer_Type) return Integer;
end CC_Test_Channel;

Тело тогда:

function Checksum(Msg : The_Transfer_Type) return Integer is
   Sum : Integer := 0;
begin
   -- calculate the checksum
   for i in 1 .. SIZE loop
      Sum := Sum + Get_Checksummable_Data(Msg, I);
   end loop;
   return Sum;
end Checksum;

Функция, которую вы предоставляете для Get_Checksummable_Data, затем относится к The_Transfer_Type и просто возвращает выбранное значение из полей компонента The_Transfer_Type.

Существует также ряд других способов установить это, например, предоставление неограниченного типа массива в качестве общего формального параметра и формальной функции для его получения - это позволяет вам также избавиться от явного формального параметра SIZE , Или вы можете написать функцию Checksum () как одну из операций над типом, с которым вы создаете экземпляр CC_Test_Channel, и затем иметь:

with function Calculate_Checksum(Msg : The_Transfer_Type) return Integer;

как один из общих формалей.

Сделай шаг назад и подумай о возможностях ...

4 голосов
/ 01 марта 2010

(перенесено из комментария, так как это стало длинным)

Ада (95 и выше) поддерживает потоки. В отличие от потоков C ++, которые в значительной степени предназначены для преобразования строк, потоки Ada предназначены в качестве общего механизма для выполнения операций с данными (обычно ввод-вывод).

Каждый объект Ada имеет атрибуты 'Write и 'Read. Есть некоторые языковые потоки (для файлового ввода / вывода), но у вас также есть возможность создавать свои собственные, получая из Ada.Streams.Root_Stream_Type . Если вы пишете свой собственный поток таким образом, есть несколько низкоуровневых подпрограмм, которые дают вам прямой доступ к данным.

Это позволяет вам записывать свои собственные потоки для выполнения таких операций, как ввод-вывод, сжатие данных, или, в вашем случае, возможно, проверка суммирования данных с шины перед загрузкой их в переменные (через «Чтение»). В прошлом я делал это сам, чтобы реализовать функцию записи / воспроизведения для нашего программного обеспечения в реальном времени. Я тоже посмотрел его для сжатия (в итоге мы не нуждались в сжатии).

3 голосов
/ 26 февраля 2010
generic 
  type The_Transfer_Type is private; 
  ...

Приведенный выше код означает, что клиент может предоставить любой тип, который придумывает, для The_Transfer_Type (при условии, что он не «ограничен»). Это также означает, что ваш универсальный тип ничего не знает о типе, кроме того, что доступно присвоение.

В универсальных типах Ada существует своего рода обратная зависимость между тем, сколько различных типов объектов может быть предоставлено для универсального параметра, и какими операциями доступны универсальные параметры для этих объектов. Например, самый открытый тип будет is limited private. Вы можете поставить любой тип для одного из них. Тем не менее, универсальный может почти ничего не делать с ним. Даже назначение не будет доступно.

Уберите «ограниченное», и вы можете выполнять назначения с ним, но могут быть предоставлены только те типы, которые могут быть назначены. С другой стороны, вы можете определить это как: type The_Transfer_Type is (<>) и тогда вы можете указать любой целочисленный или перечислимый тип, и получите такие вещи, как 'first. Если пойти еще дальше, вы можете выполнить type The_Transfer_Type is range <>, и вы получите возможность выполнять целочисленные математические операции, но сможете указывать только целочисленные числовые типы.

...