Home > Backend Development > C++ > body text

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

Barbara Streisand
Release: 2024-11-16 07:55:03
Original
386 people have browsed it

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

Can My Code Mix Apples and Oranges?

In your C project, you use numerous "usings" to clarify the intended purpose of variables, primarily for std::string identifiers like PortalId or CakeId. Your current approach allows the following:

using PortalId = std::string;
using CakeId   = std::string;

PortalId portal_id("2");
CakeId cake_id("is a lie");

portal_id = cake_id; // OK
Copy after login

But this flexibility is undesirable. You seek compile-time type checking to prevent mixing different object types while preserving the original object's functionality.

Can C Fulfill This Request?

Yes, C provides a solution for your dilemma. Using C 17 and some clever coding, it's possible to create a strongly typed identifier that prevents mixing types. The results look something like this:

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;
}
Copy after login

In this code, assignments between different types are not permitted, and adding incompatible types to containers will result in compiler errors.

What's the Secret?

The magic lies within the SAFE_TYPEDEF macro. Here's the updated version that handles all your requirements:

#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;
Copy after login

This code defines a string_id class that serves as a strongly typed identifier. It's tagged with either portal_tag or cake_tag to ensure uniqueness. The class also overloads operators like <, "==", and free functions such as to_string, <<, and hash_code.

With this implementation, you can enforce strong typing and prevent mixing types in your code. It covers all the scenarios you mentioned in your question and provides a stable solution for your requirements.

The above is the detailed content of Can C Help Me Prevent Mixing Apples and Oranges in My Code?. For more information, please follow other related articles on the PHP Chinese website!

source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Articles by Author
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template