В Аде, как я могу создать подтип записей?

если у меня есть такой тип записи:

  type ABC is record
       A : Integer;
       B : Integer;
  end record;

Как я могу создать подтип ABC с двумя типами Integer, диапазон которых указан?


person snow    schedule 10.03.2012    source источник
comment
Вы не знаете. Подтипы применимы к перечислениям, числам с плавающей запятой, целым числам и т. д., но не к записям. Если вы предоставите больше информации о своей проблеме, мы сможем помочь больше...   -  person NWS    schedule 10.03.2012
comment
subtype XYZ is ABC; является законным, но не тем, о чем просит ОП.   -  person Keith Thompson    schedule 10.03.2012


Ответы (4)


Не отвечая на ваш вопрос как таковой (как говорит NWS, вы не можете этого сделать), если вместо A и B быть целыми числами, они должны быть массивами, вы можете сделать следующее:

package Record_Subtypes is

   type Int_Data is array (Integer range <>) of Integer;

   type ABC (X_Min, X_Max, Y_Min, Y_Max : Integer) is record
      A : Int_Data (X_Min .. X_Max);
      B : Int_Data (Y_Min .. Y_Max);
   end record;

   subtype ABC_4_4 is ABC(X_Min => 1, X_Max => 4,
                          Y_Min => 1, Y_Max => 4);

   subtype ABC_1_7_3_12 is ABC (X_Min => 1, X_Max => 7,
                                Y_Min => 3, Y_Max => 12);
end Record_Subtypes;

Поля записи A и B затем используют подтип индекса, предоставленный дискриминантами записи.

Это хороший трюк, который я использовал время от времени, полезный при чтении строк переменной длины из интерфейса (например, сокета), где количество байтов для чтения предоставляется через заголовок фиксированного размера; или в случае записи варианта с дискриминантом перечисления я могу подтипировать запись к определенному варианту.

person Marc C    schedule 10.03.2012

Вы также можете использовать универсальный, например:

generic
   type Number is range <>;
package Int_Record is
   type ABC is record
      A, B : Number;
   end record;
end Int_Record;

Если вам нужны разные диапазоны для A и B, вам придется использовать два общих параметра.

Использование будет таким:

procedure Foo is
   subtype My_Int is Integer range 1 .. 3;
   package My_Int_Record is new Int_Record (Number => My_Int);
   X : My_Int_Record.ABC;
begin
   X.A := 2; -- okay
   X.B := 4; -- error!
end Foo;
person Rommudoh    schedule 13.03.2012

В Ada 2012 у нас теперь есть Dynamic_Predicate, с помощью которого мы можем наложить ограничения на подтипы следующим образом:

type ABC is record
    A : Integer;
    B : Integer;
  end record;

subtype XYZ is ABC
  with dynamic_predicate => 
  ((XYZ.A in Positive) and
   (XYZ.B not in Positive)) or else raise Constraint_Error;
person Shark8    schedule 31.10.2013
comment
(а) Я думаю, вы имеете в виду or else raise Constraint_Error! (b) где в РМ это разрешено в качестве определения аспекта? Я вижу, что GNAT GPL 2013 разрешает это (но не FSF GCC 4.8.0), и я вижу, что здесь это имеет смысл. - person Simon Wright; 31.10.2013
comment
В GNAT GPL 2013 использование конструкции or raise Constraint_Error означает, что об исключении сообщается в строке объявления, хотя трассировка показывает неудачное использование. Если вы его не укажете, при неудачном использовании будет сообщено Assert_Error, что гораздо полезнее. - person Simon Wright; 01.11.2013
comment
Да, вы правы, это должно быть or else raise. Я попытался найти конструкцию в LRM, но не нашел. (Я думаю, я узнал об этом от Рэнди на comp.lang.ada.) - person Shark8; 02.11.2013

Данный:

type ABC is record
   A : Integer;
   B : Integer;
end record;

Вы можете использовать:

type XYZ is record
   A : Positive;  -- A is subtype of ABC.A
   B : Natural;   -- B is subtype of ABC.B
end record;

  function convert(Input: ABC) return XYZ is
  begin
     return Result : XYZ:= ( A => Input.A, B => Input.B );
  -- Put your exception handling here.
  end convert;
person Shark8    schedule 15.03.2012