Как использовать тип generi c? - PullRequest
1 голос
/ 22 апреля 2020

Я работаю над примером здесь: https://www.adahome.com/rm95/rm9x-12-08.html

Я написал свои generic_stack.ads:

generic
    type Item_Type is private;
    size : Positive;

package Generic_Stack is
    procedure push( item : in Item_Type );

    function  pop return Item_Type;

    function  is_Empty return Boolean;

    STACK_EMPTY : exception;
    STACK_FULL  : exception;

end Generic_Stack;

И мои generic_stack.adb :

package body Generic_Stack
is
    type Stack_Table is array (Positive range <>) of Item_Type;
    nodes : Stack_Table( 1..size );
    index : Natural := 0;

    procedure push( item : in Item_Type )
    is
    begin
        if ( index < size )
        then
            index := index + 1;
            nodes(index) := item;
        else
            raise STACK_FULL;
        end if;
    end push;

    function pop()
    return
        Item_Type
    is
        item : Item_Type;
    begin
        if ( index > 0 )
        then
            item := nodes( index );
            index := index - 1;
        else
            raise STACK_EMPTY;
        end if;
        return item;
    end pop;

    -- function is_Empty()   removed for the sake of brevity
end Generic_Stack;

Я не совсем понимаю, как на самом деле использовать Generic_Stack.
С простым generic_stack_test.adb кодом:

with Generic_Stack;
package Stack_Int_Type is new Generic_Stack( Item_Type => Integer, Size => 32 );

procedure Generic_Stack_Test
is
    stack : Stack_Int_Type;
begin
    stack.push( 3 );
end Generic_Stack_Test;

Гнат выдает мне ошибки при компиляция:

# gnat make -gnat95 generic_stack_test.adb -o generic_stack_test
x86_64-linux-gnu-gcc-8 -c -gnat95 generic_stack_test.adb
generic_stack_test.adb:9:08: keyword "body" expected here [see file name]
generic_stack_test.adb:20:24: missing "end Stack_Int_Type;"
x86_64-linux-gnu-gnatmake-8: "generic_stack_test.adb" compilation error

Должен ли я declare Stack_Int_Type или что-то подобное? Я не понимаю, как использовать объявление внутри процедуры. Если я передаю Stack_Int_Type другой процедуре, должен ли он также объявлять тип?

Можно ли просто объявить Stack_Int_Type один раз в .ads и использовать это как обычный тип? Моя книга и веб-страницы как бы предполагают, что это должно быть объявлено каждый раз, что звучит обременительно.

Ответы [ 3 ]

3 голосов
/ 22 апреля 2020

Ваш тестовый код на самом деле состоит из двух элементов библиотеки:

with Generic_Stack;
package Stack_Int_Type is new Generic_Stack( Item_Type => Integer, Size => 32 );

объявляет пакет библиотеки Stack_Int_Type, а

procedure Generic_Stack_Test
is
    stack : Stack_Int_Type;
begin
    stack.push( 3 );
end Generic_Stack_Test;

объявляет библиотечную процедуру, которая в известном виде знает ничего о Stack_Int_Type.
Мы можем это исправить, добавив необходимые with, но (компилируя с -gnatl)

 1. with Stack_Int_Type;
 2. procedure Generic_Stack_Test
 3. is
 4.    stack : Stack_Int_Type;
               |
    >>> subtype mark required in this context
    >>> found "Stack_Int_Type" declared at stack_int_type.ads:2

 5. begin
 6.    stack.push( 3 );
       1    2
    >>> invalid prefix in selected component "stack"
    >>> prefixed call is only allowed for objects of a tagged type

 7. end Generic_Stack_Test;

Здесь происходит то, что Generic_Stack не объявляет тип, поэтому вы не можете объявить его экземпляр в строке 4; это своего рода синглтон. (Среди прочего, это означает, что он озадаченно назван: я бы назвал его Integer_Stack. Никогда не вызывайте пакет _Type; _Types, может быть.) Исправляя это,

with Generic_Stack;
package Integer_Stack is new Generic_Stack( Item_Type => Integer, Size => 32 );

и

with Integer_Stack;
procedure Generic_Stack_Test
is
begin
   Integer_Stack.push( 3 );
end Generic_Stack_Test;

Вы могли бы сделать Integer_Stack local:

with Generic_Stack;
procedure Generic_Stack_Test
is
   package Integer_Stack
   is new Generic_Stack( Item_Type => Integer, Size => 32 );
begin
   Integer_Stack.push( 3 );
end Generic_Stack_Test;
2 голосов
/ 22 апреля 2020

Ваш пакет Generic_Stack никогда не определяет тип данных стека. Процедура Pu sh и Pop - это операции со стеком. У вас должен быть тип, с которым можно работать. Есть две основные категории стеков; ограниченные стеки и неограниченные стеки. Вы должны решить, какой тип стека вы создадите sh. Обсуждение обоих типов стеков, реализованных в Ada, можно найти по адресу https://sworthodoxy.blogspot.com/2019/02/stack-abstract-data-type-using-ada.html

. В примерах, на которые есть ссылки в приведенном выше URL-адресе, вы увидите, как создавать типы стеков, которые можно использовать несколько раз. Пример из Адахоме - старый и проблемный c пример. Вы определили самую большую проблему.

1 голос
/ 22 апреля 2020

Как объяснено в другом месте, тип не определен вашей спецификацией пакета. В противном случае вы бы имели type ... is где-то после ключевого слова package. Это так просто.

Но, как объяснялось и в других местах, это не драматизм c. Ваш экземпляр пакета будет точно определять один стек, а не тип, который будет использоваться в нескольких местах. В некоторых случаях это именно то, что вам нужно. Таким образом, вы можете вызвать ваш экземплярный пакет My_Stack, который на самом деле артикулирует вокруг объекта (My_Stack.nodes, доступный только через Push & Pop).

Вам необходимо выполнить создание экземпляра Generic_Stack изнутри единицы (процедура, пакет, ...). За ее пределами это «космическое пространство» только с предложениями with и use, необходимыми для соединения с другими устройствами.

with Generic_Stack;

procedure Generic_Stack_Test
is
    package My_Stack is new Generic_Stack( Item_Type => Integer, Size => 32 );
begin
    My_Stack.push( 3 );
end Generic_Stack_Test;
...