开发者

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 li开发者_高级运维ke this:

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


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
}


Boost is the right way, but want you really want is what is coming the new C++0x standard: static asserts. Boost already implements it in boost_staticassert.


No. Given your code, 300 is converted to a char by the compiler before you ever get to see it.

The closest thing you can do is accept the argument into an integer parameter who's range is larger than your target type. Then check that the value will fit before converting. The only problem is signed versus unsigned, for which I don't think there's a general solution.

But not to worry: it's not your class's job to make sure the arguments are being supplied correctly; that would be the job of a utility type that simply doesn't exist. For better or for worse, C++ doesn't provide a clean mechanism for this because it assumes the programmer won't make these mistakes.


I would say that the direct solution to this question might be this:

   template< typename T, T X, T L, T H>
      using inside_t = 
        std::enable_if_t< (X <= H) && (X >= L), 
           std::integral_constant<T, X> >;

Applied to the OP:

    template<typename C, unsigned K>    struct X; // final {};

template<unsigned K>
struct X<char, K> final 
{
    using ascii_ordinal = inside_t<unsigned, K, 0, 127>;
    char value = char(ascii_ordinal::value);
};

Which renders really terrible CL error messages when it does the job:

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

While much less snazzy but most comfortable API might be:

template<unsigned K>
struct X<char, K> final 
{
    static_assert( K >= 0U && K <= 127U, "\n\nTeribly sorry, but value must be between 0 and 127 inclusive\n\n") ;
    char value = char(K);
};


In C++20 use std::in_range

if constexpr (std::in_range<char>(300)) {
    // ...
}

There's also intcmp to do comparisons yourself

int val = 300;
if constexpr (std::cmp_greater(val, std::numeric_limits<char>::max()))
{
    std::cout << "Overflow\n";
}
else if constexpr (std::cmp_less(val, std::numeric_limits<char>::min()))
{
    std::cout << "Underflow\n";
}
else
{
    std::cout << "In range\n";
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜