The range library proposal for the std library included size which calculated the distance between begin(r) and end(r). This value usually ends up in a ptrdiff_t. I often need to put the size of a range into much smaller size types when using C APIs and C structs. Just adding a static_cast is no sufficient as I not only want to cast the type, but ensure that the value fits.

I added size_cast. It requires an explicit ReturnType template parameter. Then it can verify that the value will fit and only then do a static_cast to coerce the value into the ResultType.

The next post will demonstrate some usage.

Implementation

maintained here


template< class ResultType, class InputType >
ResultType
size_cast(InputType size)
{
const static size_t
bitsOfPositiveRepresentationInResultType =
(sizeof(ResultType) * 8) -
static_cast<ResultType>(
std::is_signed<ResultType>::value);
const static size_t
bitsOfPositiveRepresentationInInputType =
(sizeof(InputType) * 8) -
static_cast<InputType>(
std::is_signed<InputType>::value);
typedef
std::conditional <
bitsOfPositiveRepresentationInResultType <
bitsOfPositiveRepresentationInInputType,
InputType,
ResultType
>::type
check_type;
check_type size_check = static_cast<check_type>(size);
FAIL_FAST_IF(
(false,
(std::is_signed<InputType>::value && size < 0)) ||
(size_check >> (
bitsOfPositiveRepresentationInResultType - 1)) != 0,
ERROR_INVALID_PARAMETER
);
return static_cast<ResultType>(size);
}