Impossible d'accéder à des membres d'un paramètre générique Ada

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

  •  22-09-2019
  •  | 
  •  

Question

Je suis en train d'écrire un paquet générique et l'une des opérations de contrôle nécessaires est les enregistrements de données reçus sur un bus. Le type d'enregistrement varie et il est un paramètre générique. Cependant toute tentative d'accéder aux membres du paramètre générique provoquent une erreur de compilation.

L'erreur ... (Ada 95 GNAT 2009)

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

La déclaration ...

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

Et le corps ...

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;
Était-ce utile?

La solution

Lorsque vous spécifiez qu'un paramètre générique est un type privé, bien, Ada suppose que vous l'entendez: -)

i.e.. vous n'avez pas accès à ses composants. Ada n'est pas « canard typé », il est donc hors de propos si oui ou non vous savez qu'un type instanciation pourrait en fait posséder un domaine particulier. (Comment pensez-vous que votre fonction checksum pour fonctionner si The_Transfer_Type paramètres ont été instancié avec, disons, entier?)

Une façon d'aborder est de fournir également une fonction accesseur en tant que paramètre au générique qui récupérera les données nécessaires pour, dans ce cas, calculer la somme de contrôle. Par exemple:.

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;

Le corps est alors:

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;

La fonction d'alimentation pour Get_Checksummable_Data est alors spécifique à The_Transfer_Type et retourne simplement la valeur sélectionnée dans les champs de composants The_Transfer_Type.

Il y a un certain nombre d'autres façons de régler cela aussi bien, comme la fourniture d'un type tableau sans contrainte comme paramètre formel générique et une fonction officielle pour le récupérer - ce qui vous permet d'obtenir également débarrasser du paramètre formel explicite TAILLE . Ou vous pourriez écrire une fonction Checksum () comme l'une des opérations sur le type que vous instanciation CC_Test_Channel avec, puis avez:

with function Calculate_Checksum(Msg : The_Transfer_Type) return Integer;

comme l'un des formais génériques.

Reculer, et réfléchir sur les possibilités ...

Autres conseils

(déplacé d'un commentaire, comme cela a long)

Ada (95 et versions ultérieures) prend en charge les cours d'eau. A la différence des flux de C, qui sont à peu près pour la conversion de chaîne de caractères, Ada flux sont conçus comme un mécanisme général pour effectuer des opérations sur les données (typiquement I / O).

Chaque objet Ada a des attributs de 'Write et 'Read. Il y a quelques cours d'eau fourni en langue (pour le fichier I / O), mais vous avez également la possibilité de créer votre propre en dérivant Ada.Streams.Root_Stream_Type . Si vous écrivez votre propre flux de cette façon, il y a quelques routines de bas niveau qui vous donnent un accès direct aux données.

Cela vous permet d'écrire vos propres flux pour effectuer des opérations comme E / S, la compression de données, ou dans votre cas, les données somme de contrôle peut-être du bus avant de le charger dans des variables (via « Read). Je l'ai fait moi-même dans le passé pour mettre en œuvre une fonctionnalité d'enregistrement / lecture pour notre logiciel en temps réel. Je regardais en elle pour la compression une fois de trop (nous avons fini par ne pas avoir besoin de la compression).

generic 
  type The_Transfer_Type is private; 
  ...

Le code ci-dessus signifie que le client peut fournir tout type dont ils rêvent pour The_Transfer_Type (aussi longtemps que ce n'est pas « limitée »). Cela signifie aussi que votre générique sait absolument rien sur le type, sauf que asignment est disponible.

Avec génériques Ada, il est en quelque sorte une relation inverse entre le nombre de différents types d'objets peuvent être fournis pour un paramètre générique, et quelles opérations sont avilable au générique sur ces objets. Par exemple, serait is limited private le type le plus ouvert. Vous pouvez fournir tout type whatsover pour l'un de ceux-ci. Cependant, le générique peut faire presque rien avec elle. Même la cession ne serait pas disponible.

Otez la « limitée » et vous pouvez le faire avec elle des assignations, mais uniquement des types qui peuvent être attribués peuvent être fournis. vous pouvez l'autre extrême, définir comme: type The_Transfer_Type is (<>) et vous pouvez fournir tout entier ou un type énuméré, et gagnerait des choses comme 'first. Aller encore plus loin, vous pourriez faire type The_Transfer_Type is range <>, et que vous gagnez la possibilité d'effectuer des opérations mathématiques entières, mais ne serait en mesure de fournir les types numériques entiers.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top