returning a iterator by reference - c++

I want to access my iterator class by reference
#include <iostream>
template <typename T> class binary_tree;
template <typename T>
class binary_tree_iterator {
private:
binary_tree<T>* tree;
T data;
public:
binary_tree_iterator(binary_tree<T>* t) : tree(t) {}
T& operator*() {data = tree->data(); return data;}
binary_tree_iterator& operator++() {tree = tree->get_node(); return *this;}
bool operator!=(binary_tree_iterator& rhs) {return tree->data() != rhs.tree->data();}
};
template <typename T>
class binary_tree {
private:
T t_data;
binary_tree<T>* node;
binary_tree_iterator<T>* It;
public:
binary_tree(T d) : t_data(d), node(nullptr), It(nullptr)
{}
T& data() {
return t_data;
}
void set_node(binary_tree<T>* node) {
this->node = node;
}
binary_tree<T>* get_node() {
return node;
}
binary_tree_iterator<T> begin() {
It = new binary_tree_iterator<T>(this);
return *It;
}
binary_tree_iterator<T> end() {
if(node == nullptr) {
It = new binary_tree_iterator<T>(this);
return *It;
} else {
return node->end();
}
}
};
int main() {
binary_tree<int>* tree = new binary_tree<int>(2);
tree->set_node(new binary_tree<int>(3));
//for(auto& x: *tree) <--- does not work
for(auto x: *tree) {
std::cout << x << std::endl;
}
}
The for-range loop I want to use it in looks something like for(auto& x: *tree). How do I give it a reference? Is there a standard way of doing this when creating iterators? When I return the data value I assign it to a iterator data member so I can return by reference. Will I have to do the same with my iterator? I don't imagine this is the standard way of doing this.

I want to access my iterator class by reference
How do I give it a reference?
By changing the return type of the function to be binary_tree_iterator<T>& instead of binary_tree_iterator<T>. If you do that, you'd have to store an iterator somewhere instead of returning a new one, so that you can refer to it. Presumably, it would have to be stored as a member variable.
Is there a standard way of doing this when creating iterators?
No. None of the standard containers return references to iterators.
I don't imagine this is the standard way of doing this.
Indeed. The "standard" i.e. conventional thing to do is to not return references to iterators.
The for-range loop I want to use it in looks something like for(auto& x: *tree)
There is no need to return a reference to an iterator in order to make that work. If you take a look at standard containers, you'll find that none of them return a reference to an iterator, and such loop works with all of them.
The reference in that loop is bound to the result of indirection through the iterator. So, it is the operator* that must return a reference to the pointed object. And, your operator* does indeed return a reference. That said, normally an iterator would return a reference to the object stored in the container; not a reference to copy stored in the iterator. So, that's highly unconventional.
Finish writing your iterator, and you'll find that the loop works.
In conclusion: You don't need to return iterator by reference, and you shouldn't.

Related

Is it possible to implement a DefaultIfNull function in C++?

Disclaimer: This is rather more out of curiosity than for a lack of other solutions!
Is it possible to implement a function in C++ that:
gets passed a pointer of type T
either returns a reference-like-thing to the object pointed to by T
or, if the pointer is null, returns a reference-like-thing to a default constructed T() that has some sane lifetime?
Our first try was:
template<typename T>
T& DefaultIfNullDangling(T* ptr) {
if (!ptr) {
return T(); // xxx warning C4172: returning address of local variable or temporary
} else {
return *ptr;
}
}
A second attempt was done like this:
template<typename T>
T& DefaultIfNull(T* ptr, T&& callSiteTemp = T()) {
if (!ptr) {
return callSiteTemp;
} else {
return *ptr;
}
}
This gets rid of the warning and somewhat extends the lifetime of the temporary, but it's still rather error prone, I think.
Background:
The whole thing was triggered by an access pattern that looked like this:
if (pThing) {
for (auto& subThing : pThing->subs1) {
// ...
if (subThing.pSubSub) {
for (auto& subSubThing : *(subThing.pSubSub)) {
// ...
}
}
}
}
that could be "simplified" to:
for (auto& subThing : DefaultIfNull(pThing).subs1) {
// ...
for (auto& subSubThing : DefaultIfNull(subThing.pSubSub)) {
// ...
}
}
Yes, but it's going to be ugly:
#include <stdio.h>
#include <variant>
template <class T>
struct Proxy {
private:
std::variant<T*, T> m_data = nullptr;
public:
Proxy(T* p) {
if (p)
m_data = p;
else
m_data = T{};
}
T* operator->() {
struct Visitor {
T* operator()(T* t) { return t; }
T* operator()(T& t) { return &t; }
};
return std::visit(Visitor{}, m_data);
}
};
struct Thing1 {
int pSubSub[3] = {};
auto begin() const { return pSubSub; }
auto end() const { return pSubSub + 3; }
};
struct Thing2 {
Thing1* subs1[3] = {};
auto begin() const { return subs1; }
auto end() const { return subs1 + 3; }
};
template <class T>
auto NullOrDefault(T* p) {
return Proxy<T>(p);
}
int main() {
Thing1 a{1, 2, 3}, b{4, 5, 6};
Thing2 c{&a, nullptr, &b};
auto pThing = &c;
for (auto& subThing : NullOrDefault(pThing)->subs1) {
for (auto& subSubThing : NullOrDefault(subThing)->pSubSub) {
printf("%d, ", subSubThing);
}
putchar('\n');
}
}
There isn't really a good, idiomatic C++ solution that would exactly match what you're asking for.
A language where "EmptyIfNull" would work well, is probably one that has either garbage collection, or reference counted objects. So, we can achieve something similar in C++ by using reference counted pointers:
// never returns null, even if argument was null
std::shared_pr<T>
EmptyIfNull(std::shared_pr<T> ptr) {
return ptr
? ptr
: std::make_shared<T>();
}
Alternatively, you could return a reference to an object with static storage duration. However, I would not return a mutable reference when using such technique, since one caller might modify the object to be non-empty which might be highly confusing to another caller:
const T&
EmptyIfNull(T* ptr) {
static T empty{};
return ptr
? *ptr
: empty;
}
Alternatively, you could still return a mutable reference, but document that not modifying the empty object is a requirement that the caller must obey. That would be brittle, but that's par for the course in C++.
As another alternative, I was writing a suggestion to use a type-erasing wrapper that is either a reference, or an object, but Ayxan Haqverdili has got it covered already. Tons of boilerplate though.
Some alternative designs that adjust the premise a bit more, to be suitable to C++:
Return an object:
T
EmptyIfNull(T* ptr) {
return ptr
? *ptr
: T{};
}
Let the caller provide the default:
T&
ValueOrDefault(T* ptr, T& default_) {
return ptr
? *ptr
: default_;
}
Treat a non-null argument as a pre-condition:
T&
JustIndirectThrough(T* ptr) {
assert(ptr); // note that there may be better alternatives to the standard assert
return *ptr;
}
Treat a null argument as an error case:
T&
JustIndirectThrough(T* ptr) {
if (!ptr) {
// note that there are alternative error handling mechanisms
throw std::invalid_argument(
"I can't deal with this :(");
}
return *ptr;
}
Background:
I don't think the function that you're asking for is very attractive for the background that you give. Currently, you do nothing if the pointer is null, while with this suggestion you would be doing something with an empty object. If you dislike the deeply nested block, you could use this alternative:
if (!pThing)
continue; // or return, depending on context
for (auto& subThing : pThing->subs1) {
if (!subThing.pSubSub)
continue;
for (auto& subSubThing : *subThing.pSubSub) {
// ...
}
}
Or, perhaps you could establish an invariant that you never store null in the range, in which case you never need to check for null.
Sadly, but no. There is really no way to fully achieve what you want. Your options are:
If passed pointer is nullptr, return a reference to static object. This would only be correct if you are returning a const reference, otherwise, you are exposing yourself to a huge can of worms;
Return an std::optional<std::ref> and return unset optional if pointer is nullptr. This doesn't really solve your problem, as you still have to check at the call site if the optional is set, and you might as well check for the pointer to be nullptr instead at the call site. Alternatively, you can use value_or to extract value from optional, which would be akin to next option in a different packaging;
Use your second attempt, but remove default argument. This will mandate call site to provide a default object - this makes code somewhat ugly
If you only want to skip over nullptrs easily, you could just use boost::filter_iterator.
Now, this does not return default value on null pointer occurence, but neither does OP's original code; instead it wraps the container and provides the API to silently skip it in the for loop.
I skipped all the boilerplate code for brevity, hopefully the snippet below illustrates the idea well.
#include <iostream>
#include <memory>
#include <vector>
#include <boost/iterator/filter_iterator.hpp>
struct NonNull
{
bool operator()(const auto& x) const { return x!=nullptr;}
};
class NonNullVectorOfVectorsRef
{
public:
NonNullVectorOfVectorsRef(std::vector<std::unique_ptr<std::vector<int>>>& target)
: mUnderlying(target)
{}
auto end() const
{
return boost::make_filter_iterator<NonNull>(NonNull(), mUnderlying.end(), mUnderlying.end());
}
auto begin() const
{
return boost::make_filter_iterator<NonNull>(NonNull(), mUnderlying.begin(), mUnderlying.end());
}
private:
std::vector<std::unique_ptr<std::vector<int>>>& mUnderlying;
};
int main(int, char*[])
{
auto vouter=std::vector<std::unique_ptr<std::vector<int>>> {};
vouter.push_back(std::make_unique<std::vector<int>>(std::vector<int>{1,2,3,4,5}));
vouter.push_back(nullptr);
vouter.push_back(std::make_unique<std::vector<int>>(std::vector<int>{42}));
auto nn = NonNullVectorOfVectorsRef(vouter);
for (auto&& i:nn) {
for (auto&& j:(*i)) std::cout << j << ' ';
std::cout << '\n';
}
return 0;
}
If you accept std::shared_ptr<T>, you could use them to achieve this in a rather save and portable way:
template<typename T>
std::shared_ptr<T> NullOrDefault(std::shared_ptr<T> value)
{
if(value != nullptr)
{
return value;
}
return std::make_shared<T>();
}
From the comments:
One solution would be to implement a proxy range type containing a
pointer. This type would provide the begin and end members which
either forward the call to the pointed container or provide an empty
range. The usage would be basically identical to using a NullOrEmpty
function, in the context of a range-based for loop. – François
Andrieux yesterday
This is basically similar to what Ayxan provided in another answer, though this one here does work with exactly the client side syntax shown in the OP by providing begin() and end():
template<typename T>
struct CollectionProxy {
T* ref_;
// Note if T is a const-type you need to remove the const for the optional, otherwise it can't be reinitialized:
std::optional<typename std::remove_const<T>::type> defObj;
explicit CollectionProxy(T* ptr)
: ref_(ptr)
{
if (!ref_) {
defObj = T();
ref_ = &defObj.value();
}
}
using beginT = decltype(ref_->begin());
using endT = decltype(ref_->end());
beginT begin() const {
return ref_->begin();
}
endT end() const {
return ref_->end();
}
};
template<typename T>
CollectionProxy<T> DefaultIfNull(T* ptr) {
return CollectionProxy<T>(ptr);
}
void fun(const std::vector<int>* vecPtr) {
for (auto elem : DefaultIfNull(vecPtr)) {
std::cout << elem;
}
}
Notes:
Allowing for T and T const seems a wee bit tricky.
The solution using a variant would generate a smaller proxy object size (I think).
This is certainly gonna be more expensive at runtime than the if+for in the OP, after all you have to at least construct an (empty) temporary
I think providing an empty range could be done cheaper here if all you need is begin() and end(), but if this should generalize to more than just calls to begin() and end(), you would need a real temporary object of T anyways.

Iterator for a list implemented using unique_ptr

I am creating a datastructure that uses unique_ptr. I now want to define different iterators over this datastructure, however the nodes of my data structure are part of the data itself. Because of this I want the iterators to return the actual nodes and not only the values contained within.
Here is what I got so far (much simplified example):
#include <algorithm>
#include <iostream>
#include <memory>
using namespace std;
template <typename T> struct node {
node(T val) : val(val), next(nullptr) {}
node(T val, unique_ptr<node<T>> &n) : val(val), next(move(n)) {}
T val;
unique_ptr<node<T>> next;
template <bool Const = true> struct iter {
using reference =
typename std::conditional<Const, const node<T> *, node<T> *>::type;
iter() : nptr(nullptr) {}
iter(node<T> *n) : nptr(n) {}
reference operator*() { return nptr; }
iter &operator++() {
nptr = nptr->next.get();
return *this;
}
friend bool operator==(const iter &lhs, const iter &rhs) {
return lhs.nptr == rhs.nptr;
}
friend bool operator!=(const iter &lhs, const iter &rhs) {
return lhs.nptr != rhs.nptr;
}
node<T> *nptr;
};
iter<> begin() const { return iter<>(this); }
iter<> end() const { return iter<>(); }
iter<false> begin() { return iter<false>(this); }
iter<false> end() { return iter<false>(); }
};
template <typename T> void pretty_print(const unique_ptr<node<T>> &l) {
auto it = l->begin();
while (it != l->end()) {
auto elem = *it;
cout << elem->val << endl;
++it;
}
}
int main() {
auto a = make_unique<node<int>>(4);
auto b = make_unique<node<int>>(3, a);
auto c = make_unique<node<int>>(2, b);
auto d = make_unique<node<int>>(1, c);
for (auto *elem : *d) {
elem->val = elem->val - 1;
}
pretty_print(d);
return 0;
}
Is it considered bad practice to expose the raw pointers to the elements of the datastructure in this way? Will this work in a more complex example, especially in regard to const-correctness?
This is largely opinion, but I'd say it's a bad idea. unique_ptrs should be unique; the rare exceptions should be if you need to pass a raw pointer to some other function that isn't properly templated (and you know for a fact it doesn't hold on to the pointer).
Otherwise, you're in a situation where reasonable uses, e.g. initializing to a std::vector<node<int>*> using your iterator, violate the assumptions baked into unique_ptr. In general, you want your APIs to behave predictably with limited developer headaches, and your proposal adds the headache of "You can iterate it as long as you don't store anything to anything with a lifetime beyond my custom structure's lifetime".
Better options are:
Returning references to your actual unique_ptrs (so people are able to work with them without violating the uniqueness contract; make them const if they shouldn't be mutated); they'd have to take ownership or explicitly use "borrowed" unmanaged pointers at their own risk to store the results, but iteration would work fine and they can't accidentally violate uniqueness guarantees
Store shared_ptrs internally, and hand out new shared_ptrs during iteration, so ownership is automatically shared and lifetime extends as long as a single shared pointer remains
Importantly, neither of these two options allows someone to accidentally "do the wrong thing". The caller can do bad things, but they have to personally, explicitly bypass the smart pointer protection mechanisms to do so, and that's on their head.
Of course, the third option is:
Return a reference to the value pointed to, not the pointer; if the value is stored it should be copy-constructed
It's possible for users to get this last one wrong (by storing the reference long term, taking the address of it to get a new pointer violating uniqueness guarantees, etc.), but it follows existing C++ conventions (as Ryan points out in the comments) for containers like std::vector, so it's not a new concern; C++ developers generally know not to do terrible things with references acquired from iteration. It's arguably the best option, since it maps well to the standard patterns, making it easier for developers by fitting into existing mental models.
I would use reference instead of pointer in your iterator
using reference =
typename std::conditional<Const, const node<T>&, node<T>&>::type;
So your iterator has only to be dereferencing once.
(I would keep pointer for the member though).
Pointer in (public) interface introduce a doubt about ownership.
The usage syntax would be:
for (auto& elem : *d) {
elem.val = elem.val - 1;
}
or
while (it != l->end()) {
const auto& elem = *it;
std::cout << elem.val << std::endl;
++it;
}
Your iterator indeed is invalidated when its corresponding node is released which is the common case.

Custom STL container wrapper report weird compiler error

I have a C++ library (with over 50 source files) which uses a lot of STL routines with primary containers being list and vector. This has caused a huge code bloat and I would like to reduce the code bloat by creating another library which is essentially a wrapper
over the list and vector.
I basically need a wrapper around std::list which works perfectly for the list container of any type.
Shown below is my list wrapper class.
template<typename T>
class wlist
{
private:
std::list<T> m_list;
public:
wlist();
typedef std::list<void*>::iterator Iterator;
typedef std::list<void*>::const_iterator CIterator;
unsigned int size () { return m_list.size(); }
bool empty () { return m_list.empty(); }
void pop_back () { m_list.pop_back(); }
void pop_front () { m_list.pop_front(); }
void push_front (const T& item) { m_list.push_front(item); }
void push_back (const T& item) { m_list.push_back(item); }
bool delete_item (void* item);
T& back () { return (m_list.empty()) ? NULL : m_list.back();}
T& front () { return (m_list.empty()) ? NULL : m_list.front();}
Iterator erase() { return m_list.erase(); }
Iterator begin() { return (Iterator) m_list.begin(); }
Iterator end() { return (Iterator) m_list.end(); }
};
File1.h:
class label{
public:
int getPosition(void);
setPosition(int x);
private:
wlist<text> _elementText; // used in place of list<text> _elementText;
}
File2.h:
class image {
private:
void draw image() {
//Used instead of list<label*>::iterator currentElement = _elementText.begin();
wlist<label*>::iterator currentElement = _elementText.begin();
currentElement->getPosition(); // Here is the problem.
currentElement ++;
}
}
Invoking getPosition() bombs with the following error message:
error: request for member `getPosition' in `*(&currentElement)->std::_List_iterator<_Tp>::operator-> [with _Tp = void*]()', which is of non-class type `void*'
Type casting getPosition() to label type didn't work. Additionally my iterators are of type void*.
I think the problem is that the line
currentElement->getPosition();
won't work because currentElement is an iterator over void*s, not labels. Since iterators over some type T act like T*s, this means that your currentElement iterator acts like a label**, and so writing the above code is similar to writing
(*currentElement).getPosition();
Here, the problem should be a bit easier to see - *currentElement is a label*, not a label, and so you can't use the dot operator on it.
To fix this, trying changing this code to
((label *)(*currentElement))->getPosition();
This dereferences the iterator and typecasts the void* to get a label*, then uses the arrow operator to call the getPosition() function on the label being pointed at.
Your iterator types seem to be declared in terms of std::list<void*>::iterator. This doesn't sound right to me...

Semantic of -> operator in lists (and in general C++)

My current assignment is writing a list with iterators. The list isn't being a problem so much as creating the iterator class is.
From a couple of sources I've seen that I have two operators to define in my iterator class: operator* and operator->.
Great so far! Supposing my iterator structure is so
// Nested class of List
class _Iter
{
private:
ListElem *pCurr;
const List *pList;
public:
_Iter(ListElem *pCurr, const List *list)
: pCurr_(pCurr), pList(list)
{}
T& operator*() { return pCurr_->data; }
T* operator->() { return &**this; }
};
with ListElem being
// Nested struct of List
struct ListElem
{
T data;
ListElem *next;
ListElem *prev;
};
I can see I'm doing something massively wrong (as double dereferencing of this would lead to a &(*pCurr_->data), which is not dereferencable.
My main problem is not understanding what -> is actually supposed to do in this case. Should it grant the user access to the ListElem class? If that's the case, why can't I just write
ListElem *operator->() { return pCurr_; }
instead of returning a pointer? My understanding of these two operators as used in my list (and hopefully STL lists) is that:
operator*() // Return data pointed to by iterator; pCurr_->data;
operator->() // Grant access to data-holding structure; pCurr;
Is this correct, or what am I not getting? (And does -> have a proper name?)
Whatever you do, (*something).somethingElse should be equivalent to something->somethingElse. The latter is just a short syntax for the former. Therefore,
T& operator*() { return pCurr_->data; }
T* operator->() { return &**this; }
is fine because *this just dereferences this which has the type _Iter*, not _Iter, so no operator*() call is done. Then you dereference *this, so you get pCurr->data, then you take its address, so you get &pCurr->data. But it would be much clearer to just write:
T& operator*() { return pCurr_->data; }
T* operator->() { return &pCurr->data; }
Now, this
ListElem *operator->() { return pCurr_; }
is wrong because if operator*() returns T&, operator->() should return T*, that's what it was designed for. If you really want to grant access to ListItem instead of its data (which may or may not make sense depending on the design, but in your case it looks like it doesn't), then you should also redefine operator*() to get this:
ListElem& operator*() { return *pCurr_; }
ListElem *operator->() { return pCurr_; }
Note that it is not a language requirement, it is just how you design your class to avoid confusing interface.
Your main guideline should be that
(*iter).hello();
iter->hello();
should both do the same thing. That's what the user expects. Returning ListElem gives nothing to the user. The user shouldn't even know the details of the implementation of ListElem.
operator-> gives a pointer to the object pointed to by the iterator, in this case (apparently) pCurr_->data.
T *operator->() { return &(pCurr_->data); }
It should return the address of the object returned by operator*() as a value or reference.
T &operator*() { return pCurr_->data; }
// or
T &operator*() { return *operator->(); }
operator->() exists to implement -> with iterators (with the behavior it has for pointers) and is necessary because operator* may return an object by value instead of by reference.
Note that you don't need to store a pointer to the List in the iterator to obtain the functionality required.

How to create operator-> in iterator without a container?

template <class Enum>
class EnumIterator {
public:
const Enum* operator-> () const {
return &(Enum::OfInt(i)); // warning: taking address of temporary
}
const Enum operator* () const {
return Enum::OfInt(i); // There is no problem with this one!
}
private:
int i;
};
I get this warning above. Currently I'm using this hack:
template <class Enum>
class EnumIterator {
public:
const Enum* operator-> () {
tmp = Enum::OfInt(i);
return &tmp;
}
private:
int i;
Enum tmp;
};
But this is ugly because iterator serves as a missing container.
What is the proper way to iterate over range of values?
Update:
The iterator is specialized to a particular set objects which support named static constructor OfInt (code snippet updated).
Please do not nit-pick about the code I pasted, but just ask for clarification. I tried to extract a simple piece.
If you want to know T will be strong enum type (essentially an int packed into a class). There will be typedef EnumIterator < EnumX > Iterator; inside class EnumX.
Update 2:
consts added to indicate that members of strong enum class that will be accessed through -> do not change the returned temporary enum.
Updated the code with operator* which gives no problem.
Enum* operator-> () {
tmp = Enum::OfInt(i);
return &tmp;
}
The problem with this isn't that it's ugly, but that its not safe. What happens, for example in code like the following:
void f(EnumIterator it)
{
g(*it, *it);
}
Now g() ends up with two pointers, both of which point to the same internal temporary that was supposed to be an implementation detail of your iterator. If g() writes through one pointer, the other value changes, too. Ouch.
Your problem is, that this function is supposed to return a pointer, but you have no object to point to. No matter what, you will have to fix this.
I see two possibilities:
Since this thing seems to wrap an enum, and enumeration types have no members, that operator-> is useless anyway (it won't be instantiated unless called, and it cannot be called as this would result in a compile-time error) and can safely be omitted.
Store an object of the right type (something like Enum::enum_type) inside the iterator, and cast it to/from int only if you want to perform integer-like operations (e.g., increment) on it.
There are many kind of iterators.
On a vector for example, iterators are usually plain pointers:
template <class T>
class Iterator
{
public:
T* operator->() { return m_pointer; }
private:
T* m_pointer;
};
But this works because a vector is just an array, in fact.
On a doubly-linked list, it would be different, the list would be composed of nodes.
template <class T>
struct Node
{
Node* m_prev;
Node* m_next;
T m_value;
};
template <class T>
class Iterator
{
public:
T* operator->() { return m_node->m_value; }
private:
Node<T>* m_node;
};
Usually, you want you iterator to be as light as possible, because they are passed around by value, so a pointer into the underlying container makes sense.
You might want to add extra debugging capabilities:
possibility to invalidate the iterator
range checking possibility
container checking (ie, checking when comparing 2 iterators that they refer to the same container to begin with)
But those are niceties, and to begin with, this is a bit more complicated.
Note also Boost.Iterator which helps with the boiler-plate code.
EDIT: (update 1 and 2 grouped)
In your case, it's fine if your iterator is just an int, you don't need more. In fact for you strong enum you don't even need an iterator, you just need operator++ and operator-- :)
The point of having a reference to the container is usually to implement those ++ and -- operators. But from your element, just having an int (assuming it's large enough), and a way to get to the previous and next values is sufficient.
It would be easier though, if you had a static vector then you could simply reuse a vector iterator.
An iterator iterates on a specific container. The implementation depends on what kind of container it is. The pointer you return should point to a member of that container. You don't need to copy it, but you do need to keep track of what container you're iterating on, and where you're at (e.g. index for a vector) presumably initialized in the iterator's constructor. Or just use the STL.
What does OfInt return? It appears to be returning the wrong type in this case. It should be returning a T* instead it seems to be returning a T by value which you are then taking the address of. This may produce incorrect behavior since it will loose any update made through ->.
As there is no container I settled on merging iterator into my strong Enum.
I init raw int to -1 to support empty enums (limit == 0) and be able to use regular for loop with TryInc.
Here is the code:
template <uint limit>
class Enum {
public:
static const uint kLimit = limit;
Enum () : raw (-1) {
}
bool TryInc () {
if (raw+1 < kLimit) {
raw += 1;
return true;
}
return false;
}
uint GetRaw() const {
return raw;
}
void SetRaw (uint raw) {
this->raw = raw;
}
static Enum OfRaw (uint raw) {
return Enum (raw);
}
bool operator == (const Enum& other) const {
return this->raw == other.raw;
}
bool operator != (const Enum& other) const {
return this->raw != other.raw;
}
protected:
explicit Enum (uint raw) : raw (raw) {
}
private:
uint raw;
};
The usage:
class Color : public Enum <10> {
public:
static const Color red;
// constructors should be automatically forwarded ...
Color () : Enum<10> () {
}
private:
Color (uint raw) : Enum<10> (raw) {
}
};
const Color Color::red = Color(0);
int main() {
Color red = Color::red;
for (Color c; c.TryInc();) {
std::cout << c.GetRaw() << std::endl;
}
}