Heim >Backend-Entwicklung >C++ >Kann C mir helfen, das Mischen von Äpfeln und Orangen in meinem Code zu verhindern?
Kann mein Code Äpfel und Orangen mischen?
In Ihrem C-Projekt verwenden Sie zahlreiche „Usings“, um den beabsichtigten Zweck von Variablen zu verdeutlichen , hauptsächlich für std::string-Bezeichner wie PortalId oder CakeId. Ihr aktueller Ansatz ermöglicht Folgendes:
using PortalId = std::string; using CakeId = std::string; PortalId portal_id("2"); CakeId cake_id("is a lie"); portal_id = cake_id; // OK
Aber diese Flexibilität ist unerwünscht. Sie streben eine Typprüfung zur Kompilierungszeit an, um eine Vermischung verschiedener Objekttypen zu verhindern und gleichzeitig die Funktionalität des ursprünglichen Objekts beizubehalten.
Kann C diese Anforderung erfüllen?
Ja, C bietet eine Lösung für dein Dilemma. Mit C 17 und etwas cleverer Codierung ist es möglich, einen stark typisierten Bezeichner zu erstellen, der das Mischen von Typen verhindert. Die Ergebnisse sehen etwa so aus:
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; }
In diesem Code sind Zuweisungen zwischen verschiedenen Typen nicht zulässig und das Hinzufügen inkompatibler Typen zu Containern führt zu Compilerfehlern.
Was ist das Geheimnis?
Die Magie liegt im Makro SAFE_TYPEDEF. Hier ist die aktualisierte Version, die alle Ihre Anforderungen erfüllt:
#include <iostream> #include <string> #include <map> #include <unordered_map> // define some tags to create uniqueness struct portal_tag {}; struct cake_tag {}; // a string-like identifier that is typed on a tag type template<class Tag> struct string_id { using tag_type = Tag; // needs to be default-constuctable because of use in map[] below string_id(std::string s) : _value(std::move(s)) {} string_id() : _value() {} // provide access to the underlying string value const std::string& value() const { return _value; } private: std::string _value; // will only compare against same type of id. friend bool operator < (const string_id& l, const string_id& r) { return l._value < r._value; } friend bool operator == (const string_id& l, const string_id& r) { return l._value == r._value; } // and let's go ahead and provide expected free functions friend auto to_string(const string_id& r) -> const std::string& { return r._value; } friend auto operator << (std::ostream& os, const string_id& sid) -> std::ostream& { return os << sid.value(); } friend std::size_t hash_code(const string_id& sid) { std::size_t seed = typeid(tag_type).hash_code(); seed ^= std::hash<std::string>()(sid._value); return seed; } }; // let's make it hashable namespace std { template<class Tag> struct hash<string_id<Tag>> { using argument_type = string_id<Tag>; using result_type = std::size_t; result_type operator()(const argument_type& arg) const { return hash_code(arg); } }; } // create some type aliases for ease of use using PortalId = string_id<portal_tag>; using CakeId = string_id<cake_tag>; using namespace std;
Dieser Code definiert eine string_id-Klasse, die als stark typisierte Kennung dient. Es ist entweder mit portal_tag oder cake_tag getaggt, um die Einzigartigkeit sicherzustellen. Die Klasse überlädt auch Operatoren wie <, „==" und freie Funktionen wie to_string, << und hash_code.
Mit dieser Implementierung können Sie eine starke Typisierung erzwingen und das Mischen von Typen in Ihrem verhindern Code. Es deckt alle Szenarien ab, die Sie in Ihrer Frage erwähnt haben, und bietet eine stabile Lösung für Ihre Anforderungen.
Das obige ist der detaillierte Inhalt vonKann C mir helfen, das Mischen von Äpfeln und Orangen in meinem Code zu verhindern?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!