c++metaprogrammingrange-checking

Checking at compile time if specified value is in a range of a type


Is it possible to check this:

template<class IntType,IntType value>
struct X{};

What I mean by this is, is it possible to check that value supplied by user will "fit" into IntType (which can be any of std integer types) type? For example, I would like to detect something like this:

X<char,300> a;//here 300 is out of range and I would like to be able to detect that.

Solution

  • Now that you've changed X's signature from the way it was in the original unedited question, it's easily implemented using Boost.Integer:

    #include <boost/static_assert.hpp>
    #include <boost/cstdint.hpp>
    #include <boost/integer_traits.hpp>
    
    template<
        typename IntType,
        boost::uint64_t Value,
        bool IsSigned = boost::integer_traits<IntType>::is_signed
    >
    struct validate_range;
    
    template<typename IntType, boost::uint64_t Value>
    struct validate_range<IntType, Value, true>
    {
        typedef boost::integer_traits<IntType> traits_t;
        static bool const value =
            static_cast<boost::int64_t>(Value) >= traits_t::const_min &&
            static_cast<boost::int64_t>(Value) <= traits_t::const_max;
    };
    
    template<typename IntType, boost::uint64_t Value>
    struct validate_range<IntType, Value, false>
    {
        typedef boost::integer_traits<IntType> traits_t;
        static bool const value =
            Value >= traits_t::const_min &&
            Value <= traits_t::const_max;
    };
    
    template<typename IntType, boost::uint64_t Value>
    struct X
    {
        BOOST_STATIC_ASSERT_MSG(
            (validate_range<IntType, Value>::value),
            "Value constant is out of range"
        );
    };
    
    int main()
    {
        X<char, -2> x1;             // fails iif char is unsigned by default
        X<char, 2> x2;              // fine
        X<char, 255> x3;            // fails iif char is signed by default
        X<unsigned char, -2> x4;    // fails
        X<unsigned char, 255> x5;   // fine
        X<unsigned char, 300> x6;   // fails
    }