开发者

How can the allowed range of an integer be restricted with compile time errors?

开发者 https://www.devze.com 2023-01-16 01:36 出处:网络
I would like to create a type that is an integer value, but with a restricted range. Attempting to create an instance of this type with a value outside the allowable range should cause a compile time

I would like to create a type that is an integer value, but with a restricted range. Attempting to create an instance of this type with a value outside the allowable range should cause a compile time error.

I have found examples that allow compile time errors to be triggered when an enumeration value outside those specified is used, but none that allow a restricted range of integers (without names).

Is this 开发者_开发知识库possible?


Yes but it's clunky:

// Defining as template but the main class can have the range hard-coded
template <int Min, int Max>
class limited_int {
private:
    limited_int(int i) : value_(i) {}
    int value_; 
public:
    template <int Val> // This needs to be a template for compile time errors
    static limited_int make_limited() { 
        static_assert(Val >= Min && Val <= Max, "Bad! Bad value.");
        // If you don't have static_assert upgrade your compiler or use:
        //typedef char assert_in_range[Val >= Min && Val <= Max];
        return Val;
    }

    int value() const { return value_; }
};

typedef limited_int<0, 9> digit;
int main(int argc, const char**) 
{

    // Error can't create directly (ctor is private)
    //digit d0 = 5; 

    // OK
    digit d1 = digit::make_limited<5>(); 

    // Compilation error, out of range (can't create zero sized array)
    //digit d2 = digit::make_limited<10>(); 

    // Error, can't determine at compile time if argc is in range
    //digit d3 = digit::make_limited<argc>(); 
}

Things will be much easier when C++0x is out with constexpr, static_assert and user defined literals.


Might be able to do something similar by combining macros and C++0x's static assert.

#define SET_CHECK(a,b) { static_assert(b>3 && b<7); a=b; }


A runtime integer's value can only be checked at runtime, since it only exists at runtime, but if you make a runtime check on all writing methods, you can guarantee it's contents. You can build a regular integral replacement class with given restrictions for that.

For constant integers, you could use a template to enforce such a thing.

template<bool cond, typename truetype> struct enable_if {
};
template<typename truetype> struct enable_if<true, truetype> {
    typedef truetype type;
};
class RestrictedInt {
    int value;
    RestrictedInt(int N)
        : value(N) {
    }
public:
    template<int N> static typename enable_if< (N > lowerbound) && (N < upperbound), RestrictedInt>::type Create() {
        return RestrictedInt(N);
    }
};

Attempting to create this class with a template value that isn't within the range will cause a substitution failure and a compile-time error. Of course, it will still require adornment with operators et al to replace int, and if you want to compile-time guarantee other operations, you will have to provide static functions for them (there are easier ways to guarantee compile-time arithmetic).


Well, as you noticed, there is already a form of diagnostic for enumerations.

It's generally crude: ie the checking is "loose", but could provide a crude form of check as well.

enum Range { Min = 0, Max = 31 };

You can generally assign (without complaint) any values between the minimal and maximal values defined.

You can in fact often assign a bit more (I think gcc works with powers of 2).

0

精彩评论

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

关注公众号