Skip to content


Subversion checkout URL

You can clone with
Download ZIP
This packet provides some typebuilders that will enable a better usage of the C++-typesystem
C++ Shell
Branch: master

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.

Type Builder

C++ offers a strong, static and reflexive typesystem. Such typesystems are able to increase the correctness of code by detecting errors at compiletime. As a language that supports OOP (with some flaws) many projects take advantage of this ability; however one kind of types is often used without real semantics: Build-in number-types.

Let's take a look at a pretty realistic example: Implementing a point-class. Many of us would do something like this:

template<typename T>
struct point{
    point(T x, T y): x{x}, y{y} {}

    T x;
    T y;

int main(){
    point<double> p{1.0, 2.0};
    // use p

This looks nice on the first glance. However: point.x and point.y are both of the same type, though they represent completly different things. Let's look at this code:

int main(){
    int x = 1;
    int y = 2;
    // simple to spot here; this won't be allways so:
    point<int> p{y, x};
    // use p

The error may be obvious but no compiler in the world will complain about this. The solution to this is giving point.x and point.y different types:

class x_coord{
    // MUCH stuff

class y_coord{
    // basicly exactly the same trivial stuff as in x_coord

struct point{
    point(x_coord x, y_coord y): x{x}, y{y} {}

    x_coord x;
    y_coord y;

int main(){
    x_coord x{1.0};
    y_coord y{2.0};

    // ERROR:
    // point p{y, x};

    // this works like a charm:
    point p{x, y};

So this solves the problem, but you have to write lots of trivial code for every single type when all you want is basicly integer-semantics.

This is the part where Type Builder will help you a lot. The code can be reduced to the following:

// completly distinct types (enforced by the second template-parameter)
struct x_coord_id{};
using x_coord = type_builder::basic_number<int, x_coord_id, type_builder::ENABLE_ALL_SPECIFIC_MATH>;
struct y_coord_id{};
using y_coord = type_builder::basic_number<int, y_coord_id, type_builder::ENABLE_ALL_SPECIFIC_MATH>;

struct point{
    point(x_coord x, y_coord y): x{x}, y{y} {}

    x_coord x;
    y_coord y;

int main(){
    x_coord x{1.0};
    y_coord y{2.0};

    // ERROR:
    // point p{y, x};

    // this works like a charm:
    point p{x, y};

    // use p

Current state

The library is currently in alpha-state without strong guarantees that the API won't change. Especially the interactions of the basic types with other types should be considered as something that might change in the future.

Nevertheless the performance is already identical to using the build-in types if the code is compiled with enabled optimization.

Library description

All types and constants are part of the namespace type_builder. You shouldn't do much about this because the usage-recommendation is anyway to use some kind of typedef, like in the code above.


This template-class is used to create distinct number type that serves a specific purpose. You can enable and disable several operators in different contexts (e.g. enable addition with other instances and multiplication with integral numbers but not with floating point). All arithmetic (that excludes bit-operators) operators are available but most are disabled by default. The implementations are just small wrappers around the implementation of the basetype with std::enable_if and static asserts to check whether the called function is enabled for the type in question.


The classtemplate takes four template-arguments:

  1. T = the underlying type. This may be any type that overloads the arithmetic-operators like the built-in number-types do, but the usage of the built-in ones is usually a good choice.
  2. Tid = A type (may be empty) that is used to identify the logical type. This has to be unique for every semantic type, even if they have otherwise different template-arguments (doing anything else shall be considered undefined behaviour. The recommended way is in general to create an empty one directly before the creation of the new type and using it only for this purpose (see example above).
  3. Tflags = This argument is a bitmask that will controll which operations are permitted for your type. A detailed description can be found in the description of the settings-enum below.
  4. Tbase = The template-base of the base-type of the basic_number. Protected Inheritance is used to derive from its instanciation and it is used to set the details for stream-IO.

the settings-enum

This enum contains several constants that controll the operations that are possible to use on a class-template-instance; they are designed to be used as bit-masks and there are already several combined flags.

The values of the constants are completly unspecified and may change between versions without any further notice. Don't rely on them!

The existing flags are (this might be slightly outdated but not to such a degree that it would be unusable):

  • ENABLE_GENERAL_CONSTRUCTION = Enables the construction from any type.
  • ENABLE_DEFAULT_CONSTRUCTION = Enables the default-construction.
  • ENABLE_LATE_ASSIGNEMENT = Enables late assignement from other types.
  • ENABLE_SPECIFIC_EQUALITY_CHECK = Enables an equality-check with other instances.
  • ENABLE_SPECIFIC_ORDERING = Provides the ordering with any other instances.
  • ENABLE_EQUALITY_CHECK = Enables an equality-check with most other types.
  • ENABLE_ORDERING = Provides an ordering with most other types.
  • ENABLE_INC_DEC = Enables the usage of the pre/post-increment/decrement-operators.
  • ENABLE_SPECIFIC_PLUS_MINUS = Enables addition and subtraction with other instances.
  • ENABLE_SPECIFIC_MULTIPLICATION = Enables multiplication with other instances.
  • ENABLE_ENABLE_SPECIFIC_DIVISION = Enables dividing by other instances.
  • ENABLE_INTEGER_MULTIPLICATION = Enables multiplication with integers.
  • ENABLE_INTEGER_DIVISION = Enables dividing by integers.
  • ENABLE_INTEGER_MULT_DIV = This combines the two flags above.
  • ENABLE_FLOAT_MULTIPLICATION = Enables multiplication by integers and floating-point-types.
  • ENABLE_FLOAT_DIVISION = Enables dividing by integers and floating-point-types.
  • ENABLE_FLOAT_MULT_DIV = This combines the two flags above.
  • ENABLE_GENERAL_PLUS_MINUS = Enables adding most other types.
  • ENABLE_GENERAL_MULTIPLICATION = Enables multiplication with other types.
  • ENABLE_GENERAL_DIVISION = Enables dividing by other types.
  • ENABLE_GENERAL_MULT_DIV = This combines the two flags above.
  • ENABLE_SPECIFIC_MODULO = Enables the calculation of the modulo with other instances.
  • ENABLE_MODULO = Enable the calculation of the modulo with any supporting type.
  • ENABLE_NATIVE_TYPING = Enables native type-behaviour. (eg. decltype(mytype<int> * double) === mytype<double>)
  • DISABLE_CONSTRUCTION = Disables the creation of instances.
  • DISABLE_MUTABILITY = Disables all later changes to the value of the variable.
  • DEFAULT_SETTINGS = The default settings: this enables inc/dec, specific plus/minus and integer multiplication and division
  • ENABLE_ALL_SPECIFIC_MATH = Enables all specific math.
  • ENABLE_ALL_MATH = Enables all math.
  • ENABLE_ALL = enables everything.
Something went wrong with that request. Please try again.