Não é possível acessar membros de um parâmetro genérico do Ada

StackOverflow https://stackoverflow.com/questions/2338913

  •  22-09-2019
  •  | 
  •  

Pergunta

Estou tentando escrever um pacote genérico e uma das operações necessárias é fazer a soma de verificação dos registros de dados recebidos por um barramento.O tipo de registro irá variar e é um parâmetro genérico.No entanto, qualquer tentativa de acessar os membros do parâmetro genérico causa um erro de compilação.

O erro ...(Ada 95 GNAT 2009)

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

A declaração...

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

E o corpo...

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;
Foi útil?

Solução

Quando você especifica que um parâmetro genérico é um tipo privado, bem, Ada assume que você quer dizer isso :-)

Ou seja, você não tem acesso aos seus componentes. Ada não é "pato digitado", por isso é irrelevante se você sabe ou não que um tipo instantante pode realmente possuir um campo específico. (Como você esperaria que sua função de soma de verificação funcionasse se o parâmetro the_transfer_type fosse instanciado com, digamos, inteiro?)

Uma maneira de resolver isso é também fornecer uma função de acessador como um parâmetro para o genérico que recuperará os dados necessários, neste caso, calcular a soma de verificação. Por exemplo:

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;

O corpo é então:

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;

A função que você fornece para get_checksummable_data é então específica para o_transfer_type e simplesmente retorna o valor selecionado dos campos de componentes do The_Transfer_type.

Existem várias outras maneiras de configurar isso também, como fornecer um tipo de matriz sem restrições como um parâmetro formal genérico e uma função formal para recuperá-lo-isso permite que você também se livre do parâmetro formal de tamanho explícito. Ou você pode escrever uma função de verificação () como uma das operações no tipo com o qual você está instanciando cc_test_channel e depois ter:

with function Calculate_Checksum(Msg : The_Transfer_Type) return Integer;

como um dos formais genéricos.

Dê um passo atrás e pense nas possibilidades ...

Outras dicas

(movido de um comentário, pois ficou longo)

Ada (95 e posterior) oferece suporte a streams.Ao contrário dos fluxos C++, que são basicamente para conversão de strings, Os fluxos Ada são um mecanismo geral para realizar operações em dados (normalmente E/S).

Todo objeto Ada tem 'Write e 'Read atributos.Existem alguns fluxos fornecidos pela linguagem (para E/S de arquivo), mas você também tem a capacidade de criar o seu próprio derivando de Ada.Streams.Root_Stream_Type.Se você escrever seu próprio fluxo dessa maneira, existem algumas rotinas de baixo nível que fornecem acesso direto aos dados.

Isso permite que você escreva seus próprios fluxos para realizar operações como E/S, compactação de dados, ou no seu caso, talvez somando dados do barramento antes de carregá-lo em variáveis ​​(via 'Read).Eu mesmo fiz isso no passado para implementar uma funcionalidade de gravação/reprodução para nosso software em tempo real.Também procurei compactação uma vez (acabamos não precisando da compactação).

generic 
  type The_Transfer_Type is private; 
  ...

O código acima significa que o cliente pode fornecer qualquer tipo que sonhe para o the_transfer_type (desde que não seja "limitado"). Isso também significa que seu genérico não sabe absolutamente nada sobre o tipo, exceto que o Asignment está disponível.

Com os genéricos da ADA, existe uma espécie de relação inversa entre quantos tipos diferentes de objetos podem ser fornecidos para um parâmetro genérico e quais operações são avisas para o genérico nesses objetos. Por exemplo, o tipo mais aberto seria is limited private. Você pode fornecer qualquer tipo de queda para um desses. No entanto, o genérico não pode fazer quase nada com isso. Até a tarefa não estaria disponível.

Retire o "limitado" e você pode fazer asignamentos com ele, mas apenas tipos que podem ser atribuídos podem ser fornecidos. Por outro lado, você pode defini -lo como:type The_Transfer_Type is (<>) E então você pode fornecer qualquer tipo inteiro ou enumerado, e ganharia coisas como 'first. Indo ainda mais longe, você pode fazer type The_Transfer_Type is range <>, e você obteria a capacidade de fazer operações de matemática inteira, mas só seria capaz de fornecer tipos numéricos inteiros.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top