Anoman
Anoman

Reputation: 3

Can I have an enum with unlabelled values in C++?

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?

Upvotes: 0

Views: 196

Answers (4)

Spencer
Spencer

Reputation: 2214

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.

Upvotes: 0

Tony Delroy
Tony Delroy

Reputation: 106106

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

Upvotes: 1

sehe
sehe

Reputation: 393064

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

Upvotes: 0

dlev
dlev

Reputation: 48596

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

Upvotes: 1

Related Questions