내 코드에서 사과와 오렌지를 혼합할 수 있나요?
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 중국어 웹사이트의 기타 관련 기사를 참조하세요!