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

后端 未结 5 1723
失恋的感觉
失恋的感觉 2020-12-09 22:51

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 s

相关标签:
5条回答
  • 2020-12-09 22:55

    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; }
    
    0 讨论(0)
  • 2020-12-09 22:55

    What you are asking for is a feature of Ada, but not C++. I don't believe you can restrict a range of an integer during compile time.

    0 讨论(0)
  • 2020-12-09 22:56

    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 讨论(0)
  • 2020-12-09 22:58

    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).

    0 讨论(0)
  • 2020-12-09 23:14

    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.

    0 讨论(0)
提交回复
热议问题