Rumah >pembangunan bahagian belakang >C++ >Bolehkah C Membantu Saya Mencegah Mencampurkan Epal dan Oren dalam Kod Saya?
Bolehkah Kod Saya Mencampurkan Epal dan Oren?
Dalam projek C anda, anda menggunakan banyak "penggunaan" untuk menjelaskan tujuan pembolehubah yang dimaksudkan , terutamanya untuk pengecam std::string seperti PortalId atau CakeId. Pendekatan semasa anda membenarkan perkara berikut:
using PortalId = std::string; using CakeId = std::string; PortalId portal_id("2"); CakeId cake_id("is a lie"); portal_id = cake_id; // OK
Tetapi fleksibiliti ini tidak diingini. Anda mencari semakan jenis masa kompilasi untuk mengelakkan pencampuran jenis objek yang berbeza sambil mengekalkan kefungsian objek asal.
Bolehkah C Memenuhi Permintaan Ini?
Ya, C menyediakan penyelesaian untuk dilema anda. Menggunakan C 17 dan beberapa pengekodan pintar, anda boleh mencipta pengecam ditaip kuat yang menghalang jenis pencampuran. Hasilnya kelihatan seperti ini:
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; }
Dalam kod ini, penetapan antara jenis yang berbeza tidak dibenarkan dan menambah jenis yang tidak serasi pada bekas akan mengakibatkan ralat pengkompil.
Apa Rahsianya?
Keajaiban terletak dalam makro SAFE_TYPEDEF. Berikut ialah versi terkini yang mengendalikan semua keperluan anda:
#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;
Kod ini mentakrifkan kelas string_id yang berfungsi sebagai pengecam yang ditaip kuat. Ia ditag dengan sama ada portal_tag atau cake_tag untuk memastikan keunikan. Kelas ini juga melebihkan operator seperti <, "==" dan fungsi percuma seperti to_string, <<, dan hash_code.
Dengan pelaksanaan ini, anda boleh menguatkuasakan penaipan yang kuat dan menghalang jenis pencampuran dalam anda kod. Ia merangkumi semua senario yang anda nyatakan dalam soalan anda dan menyediakan penyelesaian yang stabil untuk keperluan anda.
Atas ialah kandungan terperinci Bolehkah C Membantu Saya Mencegah Mencampurkan Epal dan Oren dalam Kod Saya?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!