首頁  >  文章  >  後端開發  >  C 可以幫助我防止在程式碼中混合蘋果和橘子嗎?

C 可以幫助我防止在程式碼中混合蘋果和橘子嗎?

Barbara Streisand
Barbara Streisand原創
2024-11-16 07:55:03388瀏覽

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

我的程式碼可以混合蘋果和橘子嗎?

在您的 C 專案中,您使用大量「使用」來闡明變數的預期用途,主要用於 std::string 識別符,例如 PortalId 或 CakeId。您目前的方法允許以下操作:

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 以確保唯一性。該類別也重載了諸如

透過此實現,您可以強制執行強類型並防止在您的程式碼中混合類型。代碼。它涵蓋了您問題中提到的所有場景,並為您的需求提供了穩定的解決方案。

以上是C 可以幫助我防止在程式碼中混合蘋果和橘子嗎?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn