Search code examples
c++templatessuppress-warningsrange-checking

Function checking if an integer type can fit a value of possibly different (integer) type


Is it possible to create a templated function that checks if a primitive data type can fit a value of potentially different primitive data type? Let's limit the scope to integer types for the moment.

More precisely: Is it possible to create a "one fit all" templated functions yet without getting compiler warnings (boolean expression always true/false, signed/unsigned comparison, unused variable) and without disabling compiler warning checks? The functions should also limit as much as possible checks at runtime (all trivial cases should be excluded at compile time). If possible, I would prefer avoiding using extensions from C++11 and the like (unless a "quick" replacement for "old" C++ exists).

Note: "value" is not known at compile time, only its type.

Example of expected behaviour:

int main(int argc, char** argv) {
    for (int i = 1; i < argc; i++) {
        const int value = atoi(argv[i]);
        std::cout << value << ": ";
        std::cout << CanTypeFitValue<int8_t>(value) << " ";
        std::cout << CanTypeFitValue<uint8_t>(value) << " ";
        std::cout << CanTypeFitValue<int16_t>(value) << " ";
        std::cout << CanTypeFitValue<uint16_t>(value) << " ";
        std::cout << CanTypeFitValue<int32_t>(value) << " ";
        std::cout << CanTypeFitValue<uint32_t>(value) << " ";
        std::cout << CanTypeFitValue<int64_t>(value) << " ";
        std::cout << CanTypeFitValue<uint64_t>(value) << std::endl;
        }
    
}

Output:

./a.out 6 1203032847 2394857 -13423 9324 -192992929

6: 1 1 1 1 1 1 1 1

1203032847: 0 0 0 0 1 1 1 1

2394857: 0 0 0 0 1 1 1 1

-13423: 0 0 1 0 1 0 1 0

9324: 0 0 1 1 1 1 1 1

-192992929: 0 0 0 0 1 0 1 0

Test your code here or here.

Check the assembly generated here.

This question was inspired by this post


Solution

  • Using numeric_limits and types defined in stdint.h

    More compact that my first solution, same efficiency.

    Drawback: one additional header to be included.

    #include <limits>
    #include <stdint.h>
    
    using std::numeric_limits;
    
    template <typename T, typename U>
        bool CanTypeFitValue(const U value) {
            const intmax_t botT = intmax_t(numeric_limits<T>::min() );
            const intmax_t botU = intmax_t(numeric_limits<U>::min() );
            const uintmax_t topT = uintmax_t(numeric_limits<T>::max() );
            const uintmax_t topU = uintmax_t(numeric_limits<U>::max() );
            return !( (botT > botU && value < static_cast<U> (botT)) || (topT < topU && value > static_cast<U> (topT)) );        
        }
    

    Assembly code generated (you can change T and U types)

    Correctness test


    Note: a constexpr version was written, but apparently it has some problems. See here and here.