Reputation: 3
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
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
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
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
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