Nel nostro progetto, usiamo un bel po 'di "usanze" per indicare esplicitamente cosa si suppone che la variabile rappresenti. Viene utilizzato principalmente per gli identificatori std::string
come PortalId
o CakeId
. Ora quello che possiamo fare attualmente èC++ Fortemente digitato usando e typedef
using PortalId = std::string;
using CakeId = std::string;
PortalId portal_id("2");
CakeId cake_id("is a lie");
portal_id = cake_id; // OK
che non ci piace. Vorremmo avere un controllo di tipo durante la compilazione per impedirci di mescolare mele e arance preservando la maggior parte dei metodi yum yum dall'oggetto originale.
Quindi la domanda è: è possibile farlo in C++ in modo tale che l'utilizzo sia vicino a quanto segue, i compiti non funzionerebbero e potremmo ancora usarlo nelle mappe e in altre cose?
SAFE_TYPEDEF(std::string, PortalId);
SAFE_TYPEDEF(std::string, CakeId);
int main()
{
PortalId portal_id("2");
CakeId cake_id("is a lie");
std::map<CakeId, PortalId> p_to_cake; // OK
p_to_cake[cake_id] = portal_id; // OK
p_to_cake[portal_id] = cake_id; // COMPILER ERROR
portal_id = cake_id; // COMPILER ERROR
portal_id = "1.0"; // COMPILER ERROR
portal_id = PortalId("42"); // OK
return 0;
}
Abbiamo già provato alcune macro in combinazione con i modelli, ma non abbiamo ottenuto ciò di cui avevamo bisogno. E per aggiungere - possiamo usare C++ 14.
EDIT: Il codice ci siamo inventati era
#define SAFE_TYPEDEF(Base, name) \
class name : public Base { \
public: \
template <class... Args> \
explicit name (Args... args) : Base(args...) {} \
const Base& raw() const { return *this; } \
};
che è brutto
e non funziona. E non funziona, voglio dire che il compilatore era ok con
.portal_id = cake_id;
EDIT2: Aggiunto explicit
parola chiave, con il quale il nostro codice funziona davvero bene per esempio. Non sono sicuro se questa sia la strada giusta da percorrere e se riguardi tutte le situazioni sfortunate.
Beh niente :-D Mi impegno a fornire il codice. – Jendas
Basta aggiungere esplicitamente prima di c-tor. – firescreamer
Se lo si fa per le stringhe, l'uso del tipo può facilmente portare a un comportamento indefinito: 'SAFE_TYPEDEF (std :: string, S); std :: string * s = new S(); cancella s; '' std :: string' non è pensato per essere usato come classe base. – Jens