In the template I have a type for index (IndexType) which is unsigned type and need to create a member for offset which could be negative but should contain all the range for the initial unsigned type. In practice this means that it must be the next larger integer signed size.
At the same time I don't want to allocate the largest possible signed type like std::ptrdiff_t to save space, since signed short could be much better fit for unsigned char in terms of memory.
I can make very complex std::conditional with sizeofs for all possible combinations, but this will be too verbose. Is there any straightforward solution for this?
At the moment I don't need sizes larger than std::ptrdiff_t, so the quest "what if you need the size larger than all build-in primitive integer types?" could be postponed.
template <typename IndexType> // Here I get unsigned type of index
struct Offset {
IndexType offs; // Here I need a type which will be signed, but enough to keep unsigned values of IndexType, but not unnecessary large
};
Since you aren't worried about the case when the unsigned type is as large as the largest signed type there is really only three cases you need to check. If the size is 1, then get a 2 size type, If the size is 2, get a 4 size type, otherwise just go with the max signed type. One way to do that is to leverage a function to get the type like: