Testing for overflow

It is allowed to construct a type-safe number from an integral value that doesn't match its underlying type:

class number_tag;

typedef x::number<unsigned short, number_tag> number_t;

number_t number{4};

Having to explicitly static_cast<unsigned short> would get old pretty quickly. As a compromise, constructing or assigning from an integral value throws an exception if the integral value cannot be represented by the number's underlying type. overflows() is available for preventative measures:

class number_tag;

typedef x::number<unsigned short, number_tag> number_t;

int n;

if (number_t::overflows(n))
{
    // n is too big to fit.
}

truncate() is a static method that checks the given value, and if it is too big to be represented by the type-safe number, the smallest or the largest value that can be represented by the type-safe number gets returned:

class number_tag;

typedef x::number<unsigned short, number_tag> number_t;

number_t n;

n=number_t::truncate(-1); // This sets n to 0

truncate() returns the underlying integer type. The parameter value gets returned, casted, if it can be represented by the underlying integer type, or the underlying integer type's minimum or maximum value, as appropriate. truncate() is also overloaded for other type-safe number instances:

class number_tag;
class bignumber_tag;

typedef x::number<unsigned short, number_tag> number_t;
typedef x::number<long long, bignumber_tag> bignumber_t;

bignumber_t bn{-1};

number_t n;

n=number_t::truncate(bn); // This sets n to 0

truncate() is also overloaded for floating point numbers, by truncating floating points outside of the range, then rounding the floating point value.