首页 > 后端开发 > C++ > 正文

C 可以帮助我防止在代码中混合苹果和橘子吗?

Barbara Streisand
发布: 2024-11-16 07:55:03
原创
386 人浏览过

 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中文网其他相关文章!

来源:php.cn
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板