如果指定的值在类型范围内,则在编译时检查

时间:2011-04-05 18:14:07

标签: c++ metaprogramming

是否可以检查:

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

我的意思是,是否可以检查用户提供的值是否“适合”IntType(可以是任何std整数类型)类型?例如,我想检测这样的事情:

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

5 个答案:

答案 0 :(得分:2)

Boost是正确的方法,但是你真正想要的是新的C ++ 0x标准:静态断言。 Boost已经在boost_staticassert中实现了它。

答案 1 :(得分:2)

现在您已经更改了X原始未编辑问题中的签名,可以使用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
}

答案 2 :(得分:1)

没有。鉴于您的代码,编译器将300转换为char,然后才能看到它。

您可以做的最接近的事情是将参数接受到一个整数参数,该参数的范围大于您的目标类型。然后在转换之前检查该值是否合适。唯一的问题是signedunsigned,我认为没有一般解决方案。

但不要担心:确保正确提供参数不是你班级的工作;这将是一个根本不存在的实用程序类型的工作。无论好坏,C ++都没有为此提供一个干净的机制,因为它假定程序员不会犯这些错误。

答案 3 :(得分:0)

我想说,这个问题的直接解决方案可能是:

   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> >;

应用于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);
};

在执行此操作时会呈现出真正可怕的CL错误消息:

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

虽然不那么时髦,但最舒适的API可能是:

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);
};

答案 4 :(得分:0)

在 C++20 中使用 std::in_range

# attach student to a user
if not User.objects.filter(username=sn):
    user = User.objects.create_user(sn, email_add)
    user.last_name = last
    user.first_name = first
    user.save()
new_student.save()
classblock.students.add(new_student)

还有 intcmp 自己做比较

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