В языке программирования ada, есть ли способ создать подтип, который принимает по-разному расположенные перечисления типа? - PullRequest
2 голосов
/ 08 января 2020

Я пытаюсь создать подтип, который принимает определенные перечисления типа, например,

type Integers_Type is (1,2,3,4,5,6,7,8,9,10);

Я хочу что-то вроде этого,

subtype Odd_Numbers_Type is Integers_Type (1,3,5,7,9);

Я понимаю, что когда мы используем ключевое слово subtype типа нам нужно использовать диапазон, но проблема в том, что перечисление не входит в серию.

Ответы [ 2 ]

7 голосов
/ 08 января 2020

Для такого типа фильтрации значений я бы использовал предикат подтипа .

В вашем случае, измените ваше перечисление в соответствии с тем, что сказал Кит:

type Integers_Type is (ONE,TWO,THREE,FOUR,FIVE,SIX,SEVEN,EIGHT,NINE,TEN);

subtype Odd_Numbers_Type is Integers_Type 
   with Static_Predicate => Odd_Numbers_Type in ONE | THREE | FIVE | SEVEN | NINE;

Если вы хотите использовать числовые типы c вместо перечисления, используйте следующее

type Integers_Type is range 1 .. 10;

subtype Odd_Numbers_Type is Integers_Type
   with Dynamic_Predicate => Odd_Numbers_Type mod 2 /= 0;

Для получения дополнительной информации вы можете прочитать обоснование

РЕДАКТИРОВАТЬ:

Для типов перечисления следующие компилируются с использованием gnatmake -gnata -gnatVa test_enum.adb , но предупреждает о строке 14 воздействия и не выполняется при выполнении из-за утверждения, выровненного для предиката stati c .

with Ada.Text_IO; use Ada.Text_IO;

Procedure Test_Enum is
   type Integers_Type is (ONE,TWO,THREE,FOUR,FIVE,SIX,SEVEN,EIGHT,NINE,TEN);

   subtype Odd_Numbers_Type is Integers_Type 
     with Static_Predicate => Odd_Numbers_Type in ONE | THREE | FIVE | SEVEN | NINE;

   Test_I : Integers_Type := TWO;
   Test_O : Odd_Numbers_Type := ONE;
begin
   Put_Line("Test_I=" & Integers_Type'Image (Test_I));
   Put_Line ("Test_O=" & Odd_Numbers_Type'Image (Test_O));
   Test_O := Test_I;
   Put_Line ("Test_O=" & Odd_Numbers_Type'Image (Test_O));
end Test_Enum;

Для целочисленных типов, используя команду компиляции gnatmake -gnata -gnatVa test_int.adb , компилятор предупреждает, что проверка завершится неудачно во время выполнения, что является подтверждением

with Ada.Text_IO; use Ada.Text_IO;

Procedure Test_Int is
   type Integers_Type is range 1 .. 10;

   subtype Odd_Numbers_Type is Integers_Type
     with Dynamic_Predicate => Odd_Numbers_Type mod 2 /= 0;

   Test_I : Integers_Type := 2;
   Test_O : Odd_Numbers_Type := 1;
begin
   Put_Line("Test_I=" & Integers_Type'Image (Test_I));
   Put_Line ("Test_O=" & Odd_Numbers_Type'Image (Test_O));
   Test_O := Test_I;
   Put_Line ("Test_O=" & Odd_Numbers_Type'Image (Test_O));
end Test_Int;

В обоих случаях удаление флага -gnata сделает программу работающей без учета предиката, поскольку утверждения деактивированы.

1 голос
/ 14 января 2020

Вы путаете перечисления и целые числа, это большая разница, если вы исходите из чего-то вроде C: в Ada перечисления не просто метки для целых чисел.

Ответ, данный Frédéri c Praca, абсолютно верен, но (а) вы можете использовать Static_Predicate на цифрах c -типов; и (b) есть способ сделать то, что вы спрашиваете в заголовке вопроса, который немного отличается от того, что вы спрашиваете в теле вопроса.

Проблема с использованием подтип-предикатов заключается в том, что вы теряете возможность использовать определенные

(a) - Static_Predicate

Type Digit_Range is 0..9;
Subtype Odd_Digit is Digit_Range
  with Static_Predicate => 1|3|5|7|9;

(b) - Позиции перечисления
В Ada есть несколько атрибутов, среди которых Pos & Val и Pred & Succ. С учетом перечисления (Type Example is (A,B,C,D,E);, вы можете сказать Example'Pos(D), который вернет 3, и вы можете сказать Example'Val(1), который вернет B.

Вы могли бы тогда комбинируйте вещи вместе, чтобы создать несколько типов, хотя это является жестким, и обычно это не то, что вы хотите сделать.

Type Base_Numeric_Range is range 0..9;
Type Odds is range 1..Base_Numeric_Range'Pos(Base_Numeric_Range'Last)) - Base_Numeric_Range'Pos(Base_Numeric_Range'First)) / 2;

-- This is from memory, and untested; so probably wrong in the details.
Function Convert(X : Base_Numeric_Range) return Odds is
        ( Odds'Val((Base_Numeric_Range'Pos(X) / 2) + 1) );
Function Convert(X : Odds) return Base_Numeric_Range is
        ( Base_Numeric_Range'Val(Odds'Pos(X) * 2 - 1) );
...