私のコードはリンゴとオレンジを混ぜることはできますか?
C プロジェクトでは、変数の意図された目的を明確にするために多数の「使用法」を使用します。 、主に PortalId や CakeId などの std::string 識別子用です。現在のアプローチでは次のことが可能です:
using PortalId = std::string; using CakeId = std::string; PortalId portal_id("2"); CakeId cake_id("is a lie"); portal_id = cake_id; // OK
しかし、この柔軟性は望ましくありません。元のオブジェクトの機能を維持しながら、異なるオブジェクト型の混合を防ぐために、コンパイル時の型チェックを求めています。
C はこの要求を実行できますか?
はい、C は解決策を提供します。あなたのジレンマのために。 C 17 といくつかの賢いコーディングを使用すると、型の混合を防ぐ、厳密に型指定された識別子を作成できます。結果は次のようになります。
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; }
このコードでは、異なる型間の代入は許可されておらず、互換性のない型をコンテナに追加するとコンパイラ エラーが発生します。
とはその秘密は?
その魔法は SAFE_TYPEDEF マクロの中にあります。すべての要件を処理する更新バージョンは次のとおりです。
#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;
このコードは、厳密に型指定された識別子として機能する string_id クラスを定義します。一意性を確保するために、portal_tag またはcake_tag のいずれかでタグ付けされます。このクラスは、<、"== などの演算子、to_string、<<、hash_code などのフリー関数もオーバーロードします。
この実装により、強い型付けを強制し、型の混合を防ぐことができます。コード。質問で述べたすべてのシナリオをカバーしており、要件に対する安定したソリューションを提供します。
以上がコード内でリンゴとオレンジが混在するのを防ぐために C を利用できますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。