Impossibile accedere ai membri di un parametro generico Ada
-
22-09-2019 - |
Domanda
Sto cercando di scrivere un pacchetto generico e una delle operazioni richieste è quello di checksum i record di dati ricevuti nel corso di un autobus. Il tipo di record varia ed è un parametro generico. Tuttavia ogni tentativo di accedere ai membri del parametro generico causano un errore di compilazione.
L'errore ... (Ada 95 GNAT 2009)
file.adb:XX no selector "Data" for private type "The_Transfer_Type" defined at file.ads:YY
La dichiarazione ...
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 il 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;
Soluzione
Quando si specifica che un parametro generico è un tipo privato, beh, Ada si assume vuoi dire che: -)
vale a dire. non si ha accesso ai suoi componenti. Ada non è " anatra digitato", quindi è irrilevante se non si sa che un tipo di creare un'istanza potrebbe effettivamente possedere un determinato campo. (Come ci si aspetterebbe la funzione di checksum a funzionare se The_Transfer_Type parametro fosse istanziato con, diciamo, Integer?)
Un modo per affrontare questo è quello di fornire anche una funzione di accesso come parametro per il generico che recupererà i dati necessari per, in questo caso, calcolare la somma di controllo. Per esempio:.
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;
Il corpo è quindi:
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 funzione si fornisce per Get_Checksummable_Data è quindi specifico per The_Transfer_Type e semplicemente restituisce il valore selezionato dai campi che compongono il The_Transfer_Type.
Ci sono un certo numero di altri modi per installare questo come bene, come fornire un tipo di matrice non vincolato come un parametro formale generico e una funzione formale di recuperarlo - questo consente di ottenere anche eliminare il parametro formale esplicito MISURA . Oppure si potrebbe scrivere una funzione di checksum () come una delle operazioni sul tipo che si sta istanziazione CC_Test_Channel con, e quindi avere:
with function Calculate_Checksum(Msg : The_Transfer_Type) return Integer;
come uno dei formali generici.
Un passo indietro, e pensare alle possibilità ...
Altri suggerimenti
(spostato da un commento, come questo ha a lungo)
Ada (95 e versioni successive) supporta flussi. Diversamente flussi C ++, che sono praticamente per la conversione di stringhe, flussi Ada sono intese come un meccanismo generale per eseguire operazioni su dati (tipicamente I / O).
Ogni oggetto Ada ha attributi 'Write
e 'Read
. Ci sono alcuni flussi lingua dotazione (per i file I / O), ma si ha anche la possibilità di creare il proprio derivando da Ada.Streams.Root_Stream_Type . Se si scrive il proprio flusso in questo modo, ci sono alcune routine di basso livello che ti danno l'accesso diretto ai dati.
Questo consente di scrivere i propri flussi di eseguire operazioni come me O, compressione / dati, o nel tuo caso forse checksum dei dati dal bus prima di caricarla in variabili (via 'Read). L'ho fatto io stesso in passato per implementare una funzionalità di registrazione / riproduzione per il nostro software in tempo reale. Ho guardato dentro per la compressione una volta di troppo (abbiamo finito per non aver bisogno della compressione).
generic
type The_Transfer_Type is private;
...
Il codice di cui sopra significa che il cliente può fornire qualsiasi tipo sognano per The_Transfer_Type (fintanto che non è "limitata"). Ciò significa anche che il vostro generico sa assolutamente nulla circa il tipo, se non che asignment è disponibile.
Con i farmaci generici Ada non v'è una sorta di una relazione inversa tra il numero di diversi tipi di oggetti possono essere forniti per un parametro generico, e quali operazioni sono avilable al generico su quegli oggetti. Ad esempio, il tipo più aperto sarebbe is limited private
. Si potrebbe fornire qualsiasi tipo whatsover per uno di quelli. Tuttavia, il generico può fare quasi nulla con esso. Anche l'assegnazione non sarebbe disponibile.
Togliete la "limitata" e si può fare asignments con esso, ma solo i tipi che possono essere assegnati possono essere forniti. All'altro estremo, si potrebbe definire come:
type The_Transfer_Type is (<>)
e poi si potrebbe fornire un numero intero tipo enumerato, e guadagnerebbe cose come 'first
. Andando ancora oltre, si potrebbe fare type The_Transfer_Type is range <>
, e che ci si guadagna la possibilità di fare operazioni matematiche interi, ma sarebbe solo in grado di fornire interi tipi numerici.