Non esiste una soluzione completamente generale. Le clausole di rappresentazione dell'enumerazione sembrano essere progettate per rendere queste informazioni difficili da ottenere.
questo:
function Rep is new Ada.Unchecked_Conversion(Enum, Integer);
rischia di funzionare nella maggior parte dei casi, ma ci sono alcuni avvertimenti seri: i valori di rappresentanza devono essere all'interno della gamma Integer'First..Integer'Last
, e se le dimensioni di Enum
e Integer
Non la corrispondenza con il risultato è in realtà definita dall'implementazione (ma funziona con GNAT).
Come dice Simon Wright, RM raccomanda Unchecked_Conversion
, ma questa non è una soluzione molto soddisfacente e la determinazione di un tipo di obiettivo coerente è difficile.
Alla RM 2007, il livello raccomandato di supporto è:
L'attuazione dovrebbe sostenere almeno i codici interni nella gamma System.Min_Int..System.Max_Int.
che significa che la conversione in Integer
non è sempre sufficiente; un valore potrebbe essere inferiore a Integer'First
o superiore a Integer'Last
. E anche se tutti i valori si trovano in quell'intervallo, non esiste un modo veramente valido per determinare un tipo di destinazione della stessa dimensione del tipo di enumerazione. Ad esempio, questo:
type Enum is (Ten, Twenty, Thirty);
for Enum use (10, 20, 30);
function Rep is new Ada.Unchecked_Conversion(Enum, Integer);
produce questo avvertimento in GNAT:
warning: types for unchecked conversion have different sizes
Ma dopo l'avvertimento, Rep fa ritorno i valori attesi 10, 20, e 30.
La RM afferma esplicitamente che se i formati di origine e destinazione di un'istanza di Unchecked_Conversion non corrispondono, e il tipo di risultato è scalare,
il risultato della funzione è definita attuazione, e può avere un rappresentazione valida
Quindi il fatto che i lavori di cui sopra per GNAT non significa che è garantito il funzionamento in tutto il mondo.
Per un'implementazione che solo supporta i valori nella gamma System.Min_Int..System.Max_Int
, si può fare qualcosa di simile:
type Enum is (...);
for Enum use (...);
type Longest_Integer is range System.Min_Int .. System.Max_Int;
function Rep is new Ada.Unchecked_Conversion(Enum, Longest_Integer);
e ignorare l'avviso. Ma i compilatori sono consentito per accettare valori maggiori di System.Max_Int, purché siano all'interno dell'intervallo di un determinato tipo intero. Ad esempio, GNAT rifiuta questo, ma un altro compilatore Ada potrebbe accettarlo:
type Longest_Unsigned is mod System.Max_Binary_Modulus;
type Unsigned_Enum is (Zero, Huge);
for Unsigned_Enum use (0, Longest_Unsigned'Last);
e un Unchecked_Conversion da questo a qualsiasi tipo intero con segno non funzionerà. E hai ancora il potenziale problema dei risultati definiti dall'implementazione se le dimensioni non corrispondono.
Ecco una soluzione generica che dovrebbe funzionare per qualsiasi tipo di enumerazione se (a) i valori di rappresentanza sono nell'intervallo System.Min_Int..System.Max_Int
, e (b) se l'implementazione di Unchecked_Conversion
è meglio comportati rispetto allo standard Ada richiede di essere :
type Longest_Signed is range System.Min_Int .. System.Max_Int;
generic
type Enum is (<>);
function Generic_Rep(E: Enum) return Longest_Signed;
function Generic_Rep(E: Enum) return Longest_Signed is
function Rep is new Ada.Unchecked_Conversion(Enum, Longest_Signed);
begin
return Rep(E);
end Generic_Rep;
Dato tutto questa confusione, si potrebbe considerare l'utilizzo di un meccanismo diverso da clausole di rappresentazione di enumerazione di fare quello che stai cercando di fare.
risposta molto buona e informativa! – oenone
Ottima risposta. Non dimenticare, puoi anche fare il contrario (int enum) e verificare la validità con 'valido! – NWS
Risposta molto bella. Una nota: l'avviso "diverse dimensioni" può essere evitato se si crea un nuovo tipo intero e si specifica lo stesso attributo Dimensione sia per Enum che per intero. 'type Unsigned_Byte è il nuovo intervallo naturale 0 .. 255; per Unsigned_Byte'Dimensione utilizza 8; \t per Enum'Size utilizzare 8; ' –