{"id":13729886,"url":"https://github.com/doom/strong_type","last_synced_at":"2025-05-08T02:30:51.597Z","repository":{"id":215949014,"uuid":"154881210","full_name":"doom/strong_type","owner":"doom","description":"C++ implementation of strong types","archived":false,"fork":false,"pushed_at":"2019-12-02T08:18:25.000Z","size":26,"stargazers_count":54,"open_issues_count":1,"forks_count":6,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-11-14T20:38:40.088Z","etag":null,"topics":["cpp","metaprogramming","strongly-typed","types"],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/doom.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2018-10-26T18:56:14.000Z","updated_at":"2024-04-01T02:08:33.000Z","dependencies_parsed_at":null,"dependency_job_id":"17efdc4e-2394-42e0-933b-e2913357a7d8","html_url":"https://github.com/doom/strong_type","commit_stats":null,"previous_names":["doom/strong_type"],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doom%2Fstrong_type","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doom%2Fstrong_type/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doom%2Fstrong_type/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doom%2Fstrong_type/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/doom","download_url":"https://codeload.github.com/doom/strong_type/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252986619,"owners_count":21836196,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cpp","metaprogramming","strongly-typed","types"],"created_at":"2024-08-03T02:01:06.803Z","updated_at":"2025-05-08T02:30:51.357Z","avatar_url":"https://github.com/doom.png","language":"C++","readme":"# strong_type\nC++ implementation of strong types\n\n|         Build Status         |      |\n|------------------------------|------|\n| Linux (gcc-8, clang-8) / OSX | [![Build Status](https://travis-ci.com/doom/strong_type.svg?branch=master)](https://travis-ci.com/doom/strong_type) |\n\n## \u003ca name=\"table-of-contents\"\u003e\u003c/a\u003eTable of contents\n\n- [Table of contents](#table-of-contents)\n- [What is this ?](#what-is-this)\n- [A tour of the library](#library-tour)\n  - [A minimal example](#minimal-example)\n  - [Adding expressiveness](#adding-expressiveness)\n  - [Adding strong typing](#adding-strong-typing)\n  - [Customizing behavior](#customizing-behavior)\n- [Examples](#examples)\n  - [The easy way](#the-easy-way)\n  - [The customizable way](#the-customizable-way)\n- [Built-In traits](#built-ins)\n\n## \u003ca name=\"what-is-this\"\u003e\u003c/a\u003eWhat is this ?\n\nThis tiny library provides a way to wrap an existing type in order to give it additional meaning.\nIf you are already familiar with the concept of strong types, you can skip directly to the [Examples](#examples) section.\n\nOtherwise, read along !\n\n## \u003ca name=\"library-tour\"\u003e\u003c/a\u003eA tour of the library\n\n#### \u003ca name=\"minimal-example\"\u003e\u003c/a\u003eA minimal example\n\nLet's take a basic example: we want to represent **a distance** in our code.\n\nThe immediate idea we could have would be to use an integral type, such as `int`:\n\n```c++\nint distance_from_a_to_b = 10;\n```\n\nHowever, the type of the variable we work with **does not convey any information** about what its value actually represents. The only thing it tells us is how it is implemented. As a programmer reading the above code, you would need to rely on the name of the variable in order to understand the code.\n\n#### \u003ca name=\"adding-expressiveness\"\u003e\u003c/a\u003eAdding expressiveness\n\nThis can be easily fixed using a type alias:\n\n```c++\nusing distance = int;\ndistance from_a_to_b = 10;\n```\n\nThat way, our code is **more expressive**, and **easier to read** for humans.\n\nBut we still have an issue ! From the compiler's point of view, the `int` and `distance` types are identical. This can lead to error-prone constructs:\n\n```c++\nint definitely_not_a_distance = 10;\ndistance from_a_to_b = definitely_not_a_distance; // Ouch !\n```\n\nThe code above is **not correct**, because it allows converting `definitely_not_a_distance` (which is clearly, *not a distance*) to a `distance` object implicitly.\n\nThis is the first case for which this library can help: it can \"hide\" the real nature of a type, in order to prevent errors and unwanted conversions.\n\n#### \u003ca name=\"adding-strong-typing\"\u003e\u003c/a\u003eAdding strong typing\n\nIn order to fully hide the implementation of a type, we use the `st::type` wrapper. It takes two (or more, but wait !) template parameters : **the type to wrap**, and **a tag** to guarantee its uniqueness.\n\n```c++\nusing distance = st::type\u003cint, struct distance_tag\u003e;\n```\n\n*Note: the tag can be any type, as long as it is only used as tag by a single strong type*\n\nNow, both the programmer and the compiler can distinguish a `distance` from a regular `int`.\n\n```c++\nint definitely_not_a_distance = 10;\nint a_distance_value = 10;\n// distance from_a_to_b = definitely_not_a_distance; // Not OK, would not compile\ndistance from_a_to_b = distance(a_distance); // OK\ndistance copy = from_a_to_b; // OK\n```\n\nAs shown below, it is also possible to access the internal value of the strong type:\n\n```c++\nauto distance_value = from_a_to_b.value();\n```\n\n#### \u003ca name=\"customizing-behavior\"\u003e\u003c/a\u003eCustomizing behavior\n\nNow that we created a new type that hides its underlying implementation, we also lost access to the operations supported by the underlying type.\n\nWhy is that so ? Well, in our case, the concept represented by `distance` might not support all the operations allowed by the `int` type. For example, while you can add two distances together to make a longer distance, you clearly **cannot** multiply a distance with another distance. However, you can multiply a distance with a regular number, in order to scale it.\n\nIn order to customize the behavior of our strong types, this library uses the concept of **traits**. Traits are features that can be added to a type in order to give it additional behavior. Some basic traits are provided directly by the library (see the [Built-In traits](#built-ins) section), but it is also possible to write your own.\n\nA strong type can use traits like below:\n\n```c++\nusing distance = st::type\u003cint, struct distance_tag,\n\tst::addable, // distances can be added together\n\tst::multiplicable_with\u003cint\u003e // distances can be scaled by a given factor\n\u003e;\n```\n\n## \u003ca name=\"examples\"\u003e\u003c/a\u003eExamples\n\nThis library provides two different ways to define strong types, each with different levels of complexity and flexibility.\n\n#### \u003ca name=\"the-easy-way\" \u003e\u003c/a\u003eThe easy way\n\nThis is the preferred way to create a basic strong type. It requires a type tag in order to guarantee the strength of the `using` alias. Custom behavior can only be added through traits. \n\n```c++\nusing integer = st::type\u003c\n    int,\n    struct integer_tag,\n    st::arithmetic,\n    st::addable_with\u003cint\u003e\n\u003e;\n```\n\n#### \u003ca name=\"the-customizable-way\"\u003e\u003c/a\u003eThe customizable way\n\nThis way makes it easier to customize a strong type because it skips the `st::type` intermediate. Therefore, it requires creating a structure manually, which also allows defining custom member functions without having to use traits. However, traits are still available through inheritance.\n\n```c++\nstruct int_with_a_member :\n    public st::type_base\u003cint\u003e,\n    public st::traits::arithmetic\u003cint_with_a_member\u003e\n{\n    using st::type_base\u003cint\u003e::type_base;\n\n    constexpr bool is_zero() const noexcept\n    {\n        return value() == 0;\n    }\n};\n```\n\n## \u003ca name=\"built-ins\"\u003e\u003c/a\u003eBuilt-In traits\n\nThe table below describes the built-in traits that can be applied to a given strong type `T`. Unless specified otherwise, these traits just forward the requested operation to the underlying types.\n\n| Trait                     | Behavior                                                     |\n| ------------------------- | ------------------------------------------------------------ |\n| `addable`                 | Two `T` objects can be added to obtain a new `T`.            |\n| `addable_with\u003cU\u003e`         | A `T` object can be added with a `U` object to obtain a new `T`. |\n| `subtractable`            | A `T` object can be subtracted from another `T` object to obtain a new `T` |\n| `subtractable_to\u003cU\u003e`      | A `T` object can be subtracted from another `T` object to obtain a new `U`. |\n| `multiplicable`           | Two `T` objects can be multiplied to obtain a new `T`.       |\n| `multiplicable_with\u003cU\u003e`   | A `T` object can be multiplied with a `U` object to obtain a new `T`. |\n| `dividable`               | A `T` object can be divided by another `T` object to obtain a new `T`. |\n| `dividable_by\u003cU\u003e`         | A `T` object can be divided by a `U` object to obtain a new `T`. |\n| `dividable_to\u003cU\u003e`         | A `T` object can be divided by another `T` object to obtain a new `U`. |\n| `modulable`               | A `T` object can be moduled from another `T` object to obtain a new `T`. |\n| `incrementable`           | A `T` object can be pre-incremented and post-incremented.    |\n| `decrementable`           | A `T` object can be pre-decremented and post-decremented.    |\n| `equality_comparable`     | Two `T` objects can be compared for equality (supports `==` and `!=`). |\n| `orderable`               | Two `T` objects can be ordered (supports `\u003c`, `\u003e`, `\u003c=`, `\u003e=`). |\n| `arithmetic`              | Shorthand trait for `addable`, `subtractable`, `multiplicable`, `dividable`, `modulable`, `incrementable`, `decrementable`, `equality_comparable` and `orderable`. |\n| `bitwise_orable`          | Two `T` objects can be bitwise `OR`-ed to obtain a new `T`.  |\n| `bitwise_orable_with\u003cU\u003e`  | A `T` object can be bitwise `OR`-ed with a `U` object to obtain a new `T`. |\n| `bitwise_andable`         | Two `T` objects can be bitwise `AND`-ed to obtain a new `T`. |\n| `bitwise_andable_with\u003cU\u003e` | A `T` object can be bitwise `AND`-ed with a `U` object to obtain a new `T`. |\n| `bitwise_xorable`         | Two `T` objects can be bitwise `XOR`-ed to obtain a new `T`. |\n| `bitwise_xorable_with\u003cU\u003e` | A `T` object can be bitwise `XOR`-ed with a `U` object to obtain a new `T`. |\n| `bitwise_negatable`       | A `T` object can be bitwise negated (`NOT`) to obtain a new `T`. |\n| `bitwise_manipulable`     | Shorthand trait for `bitwise_orable`,`bitwise_orable_with`, `bitwise_andable`, `bitwise_andable_with`, `bitwise_xorable`, `bitwise_xorable_with`, `bitwise_negatable` and `bitwise_manipulable`. |\n| `hashable`                | A `T` object can be hashed using `std::hash` (provided that its underlying type can be hashed using `std::hash`). |\n","funding_links":[],"categories":["C++"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdoom%2Fstrong_type","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdoom%2Fstrong_type","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdoom%2Fstrong_type/lists"}