>백엔드 개발 >C++ >C가 내 코드에 사과와 오렌지가 섞이는 것을 방지할 수 있나요?

C가 내 코드에 사과와 오렌지가 섞이는 것을 방지할 수 있나요?

Barbara Streisand
Barbara Streisand원래의
2024-11-16 07:55:03445검색

 Can C   Help Me Prevent Mixing Apples and Oranges in My Code?

내 코드에서 사과와 오렌지를 혼합할 수 있나요?

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&amp; value() const { return _value; }
private:
    std::string _value;

    // will only compare against same type of id.
    friend bool operator < (const string_id&amp; l, const string_id&amp; r) {
        return l._value < r._value;
    }

    friend bool operator == (const string_id&amp; l, const string_id&amp; r) {
        return l._value == r._value;
    }

    // and let's go ahead and provide expected free functions
    friend
    auto to_string(const string_id&amp; r)
    -> const std::string&amp;
    {
        return r._value;
    }

    friend
    auto operator << (std::ostream&amp; os, const string_id&amp; sid)
    -> std::ostream&amp;
    {
        return os << sid.value();
    }

    friend
    std::size_t hash_code(const string_id&amp; 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&amp; 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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.