0

Basically I want to restrict variables to the values 0, 1 or 2.

I have tried doing this with the following:

enum Value
{
    0,
    1,
    2
};
Value var;

But this is a compile error because the enum values are unlabelled. It just makes the code less readable to assign names like "ZERO", "ONE" and "TWO" rather than referring to the values as 0, 1 and 2. Is there any way around this or should I just get rid of the enum and enforce the rule elsewhere?

Anoman
  • 3
  • 1
  • 8
    It's called `int`...? – sehe May 17 '11 at 01:24
  • 2
    If you can, I'd suggest declaring your variables as private members of a class, and then providing public setter methods that enforce the constraint. – aroth May 17 '11 at 01:25
  • Sounds like you want a utility type as I've described in the past [here](http://stackoverflow.com/questions/3181766/how-far-to-go-with-a-strongly-typed-language/3181803#3181803) – GManNickG May 17 '11 at 01:26
  • Keep in mind that there are languages that supports what the OP wants, e.g `type MySmallInt is range 0 .. 2;` in ADA. It's quite cumbersome implementing something similar in C++ though. – Lyke May 17 '11 at 01:41
  • 1
    Even if you named them `ZERO, ONE, TWO`, the enum would still be able to hold `ONE | TWO`, i.e. 3. – MSalters May 17 '11 at 07:29

4 Answers4

1

If you want to use enum, then you need to name them. Since you're just working with integer values, and you apparently want them to actually represent integer values, your best bet is it use an int parameter, and do a quick check at the top of the method. A comment on the method specifying this constraint would be welcome.

Note that if your values actually correspond to non-numeric settings, then you should just come up with good names and use the enum

dlev
  • 48,024
  • 5
  • 125
  • 132
1

Just because you add identifiers for the values doesn't mean you have to use them... you can use Value(0), Value(2) etc. if that's more convenient, but there is a danger: enum doesn't restrict the value stored to those listed... e.g. it won't protect you against Value(3).

Inside structs/classes you can use bit fields to restrict the storage used for numbers, but even then: - the range has to correspond to either the signed or unsigned values possible in the number of bits requested - attempts to assign other values will result in high order bits being removed rather than any kind of compile- or run-time error

If your intention is to create a distinct type that enforces a restricted values 0 through 2, then you need a class with specialised constructor and assignment operators:

template <int MIN, int MAX>
class Bound
{
  public:
    explicit Bound(int n) { *this = n; }

    Bound& operator=(int n)
    {
        if (n < MIN or n > MAX)
            throw std::runtime_error("out of bounds");
        n_ = n;
        return *this;
    }
    Bound& operator+=(int n) { *this = n_ + n; }

    // should "+" return int or Bound?  entirely usage dependent...
    Bound operator+(int n) { return Bound(n_ + n); }

    // -=, -, *=, *, /=, /, %=, %, bitwise ops, pre/post ++/-- etc...

    operator int() const { return n_; }

  private:
    int n_;
};
Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
0

You are looking for the builtin int type, AFAICT

If you really want to behave like a Java programmer use ADT religiously, you can always:

template <typename ordinal=int>
struct Value
{
    ordinal _val;
    /*implicit*/ Value(ordinal val) : _val(val) {}
    /*implicit*/ operator const ordinal&() const { return _val; }
    /*implicit*/ operator       ordinal&()       { return _val; }
};

int main()
{
    Value<> x = 3;
    int y = x;
    x = y;

    x += 17;
    x++;

    return x;
}

This will return 22

Of course, it is entirely possible to make the Value<> less generic and more useful in many ways, but you didn't really tell us anything about what you want with that

sehe
  • 374,641
  • 47
  • 450
  • 633
  • 1
    But just using an `int` doesn't give the OP what he wants. He's looking for a way to have an `int` variable that only accepts the values 0, 1, and 2. – aroth May 17 '11 at 01:54
  • @aroth: an enum hardly guarantees that __and__ like I said, you could summon up all kinds of constraints in the wrapper struct; in absense of stated requirements I wasn't going to make them up, and it seems @GMan already posted **[a good example](http://stackoverflow.com/questions/3181766/how-far-to-go-with-a-strongly-typed-language/3181803#3181803)** elsewhere – sehe May 17 '11 at 07:25
0

My technique for this is

#if (defined(min) || defined(max))
#error This isn't the 1990s.  Don't define macros like this.
#endif

enum class MyEnum
{
  min=0,
  max=2
};

An enum intended to operate like a number won't have any other labels.

The use of generic names like min and max let the reader know the names aren't nominal labels for the enum's values, and also cues them in on the allowed range.

You can also use SFINAE to detect the limits rather than have to specialize an enum_traits for every enumerated type.

Spencer
  • 1,924
  • 15
  • 27