Prima di tutto, il sistema LLVM è estremamente specifico e non è affatto una sostituzione drop-in per il sistema RTTI.
Locali
- Per la maggior parte delle classi, non è necessario per generare le informazioni RTTI
- Quando è necessario, le informazioni che ha senso solo all'interno di una determinata gerarchia
- Abbiamo esclude multi-eredità questo sistema
Identificare una classe oggetto
Prendere una gerarchia semplice, ad esempio:
struct Base {}; /* abstract */
struct DerivedLeft: Base {}; /* abstract */
struct DerivedRight:Base {};
struct MostDerivedL1: DerivedLeft {};
struct MostDerivedL2: DerivedLeft {};
struct MostDerivedR: DerivedRight {};
Creeremo un enum specifico per questa gerarchia, con un membro enum per ciascuno degli Stati gerarchia che può essere un'istanza (gli altri sarebbe inutili).
enum BaseId {
DerivedRightId,
MostDerivedL1Id,
MostDerivedL2Id,
MostDerivedRId
};
Poi, la classe Base
sarà aumentata con un metodo che restituirà questo enum.
struct Base {
static inline bool classof(Base const*) { return true; }
Base(BaseId id): Id(id) {}
BaseId getValueID() const { return Id; }
BaseId Id;
};
E ogni classe concreta è aumentata troppo, in questo modo:
struct DerivedRight: Base {
static inline bool classof(DerivedRight const*) { return true; }
static inline bool classof(Base const* B) {
switch(B->getValueID()) {
case DerivedRightId: case MostDerivedRId: return true;
default: return false;
}
}
DerivedRight(BaseId id = DerivedRightId): Base(id) {}
};
Ora, è possibile, semplicemente, per interrogare il tipo esatto, per la fusione.
Nascondere i dettagli di implementazione
Avendo gli utenti murking con getValueID
sarebbe problematico, però, così in questo LLVM è nascosto con l'uso di metodi di classof
.
Una determinata classe deve implementare due metodi classof
: uno per la sua base più profonda (con un test dei valori appropriati di BaseId
) e uno per sé (ottimizzazione pura). Per esempio:
struct MostDerivedL1: DerivedLeft {
static inline bool classof(MostDerivedL1 const*) { return true; }
static inline bool classof(Base const* B) {
return B->getValueID() == MostDerivedL1Id;
}
MostDerivedL1(): DerivedLeft(MostDerivedL1Id) {}
};
In questo modo, siamo in grado di verificare se un cast è possibile o non attraverso i modelli:
template <typename To, typename From>
bool isa(From const& f) {
return To::classof(&f);
}
Immaginate per un momento che To
è MostDerivedL1
:
- se
From
è MostDerivedL1
, quindi invochiamo il primo sovraccarico di classof
e funziona
- se
From
è altro, quindi invochiamo il secondo sovraccarico di classof
e il controllo utilizza l'enum per determinare se il tipo di calcestruzzo corrisponde.
Spero sia più chiaro.
È una domanda C# o C++? –
@Will: buona cattura. Ho avuto il tag completamente sbagliato –
evviva.Hai dato un'occhiata alla fonte per i modelli? –