patterncppMinor
Iterable enum class in C++11
Viewed 0 times
enumclassiterable
Problem
For a small project I'm working on, I've been looking for an iterable
The client simply creates a
I'm just looking for any tips on how I could implement this better. Does this code follow C++11 best practices? Are there any problems I've overlooked?
```
// enum.h
#ifndef ENUM_H_
#define ENUM_H_
#include
#include
#include
#include
#include
template
class Enum {
private:
// Comparator used to determine enum item ordering
struct EnumLTComparator {
bool operator() (const T e1, const T e2) {
return e1->value() value();
}
};
public:
typedef std::set ItemsSet;
typedef typename ItemsSet::size_type set_size_type;
typedef typename ItemsSet::const_iterator const_iterator;
typedef typename ItemsSet::const_reverse_iterator const_r_iterator;
int value() const { return value_; }
static set_size_type size() { return items_.size(); }
// Iteration
static const_iterator begin() { return items_.cbegin(); }
static const_iterator end() { return items_.cend(); }
static const_r_iterator rbegin() { return items_.crbegin(); }
static const_r_iterator rend() { return items_.crend(); }
bool operator== (T e2) const {return this->value() ==
enum-like class in C++, since neither C-style nor scoped enums seem to support iteration in a way that isn't hack-y. I stumbled across this (relatively) old article, from which I've drawn inspiration to create a robust Enum class supporting iteration and C++11 features.The client simply creates a
DEnum class, which includes the desired enum items as static const members, inheriting from this Enum class. This prevents code using DEnum from creating new items. Local object copies of the enum items can be created through the default copy and copy-assignment ctors. I've also added a function that allows creation of a local subset of the enum items, which also supports iteration (including using range-for syntax). The class should be type-safe in preventing type conversion of its members and instantiated copies.I'm just looking for any tips on how I could implement this better. Does this code follow C++11 best practices? Are there any problems I've overlooked?
```
// enum.h
#ifndef ENUM_H_
#define ENUM_H_
#include
#include
#include
#include
#include
template
class Enum {
private:
// Comparator used to determine enum item ordering
struct EnumLTComparator {
bool operator() (const T e1, const T e2) {
return e1->value() value();
}
};
public:
typedef std::set ItemsSet;
typedef typename ItemsSet::size_type set_size_type;
typedef typename ItemsSet::const_iterator const_iterator;
typedef typename ItemsSet::const_reverse_iterator const_r_iterator;
int value() const { return value_; }
static set_size_type size() { return items_.size(); }
// Iteration
static const_iterator begin() { return items_.cbegin(); }
static const_iterator end() { return items_.cend(); }
static const_r_iterator rbegin() { return items_.crbegin(); }
static const_r_iterator rend() { return items_.crend(); }
bool operator== (T e2) const {return this->value() ==
Solution
You are no longer using the enum properties.
But rather a set of const values that have been put in a set. Sort of defeats the purpose of enum in my mind.
I would just create a class for iterating across enums.
This is what I would have done.
Usage:
Run
Combine this with a previous printing of enum done here
Conversion between enum and string in C++ class header
const Color Color::blue(0);
const Color Color::green(1);
const Color Color::red(2);
const Color Color::white(3);
const Color Color::yellow(4);
const Color Color::multicolor(5);
const Color Color::hidden(6);But rather a set of const values that have been put in a set. Sort of defeats the purpose of enum in my mind.
I would just create a class for iterating across enums.
This is what I would have done.
#include
#include
#include
template
struct EnumIter : public std::iterator
{
static constexpr T values[] = {args...};
static constexpr std::size_t size = sizeof...(args);
int pos;
EnumIter() // No value is end
: pos(size)
{}
EnumIter(T val)
: pos(std::distance(&values[0], std::find(&values[0], &values[size], val)))
{}
const T& operator*() const {return values[pos];}
EnumIter& operator++() {++pos;return *this;}
EnumIter operator++(int) {EnumIter r(*this);this->operator++();return r;}
bool operator==(EnumIter const& rhs) {return pos == rhs.pos;}
bool operator!=(EnumIter const& rhs) {return pos != rhs.pos;}
};
template
constexpr T EnumIter::values[];Usage:
enum Ace { One = 101, Two = 233, Three = 455};
typedef struct EnumIter AceIter;
int main()
{
for(AceIter loop(One); loop != AceIter(); ++loop)
{
std::cout (*loop) << "\n";
}
}Run
> g++ -std=c++11 enum.cpp
> ./a.out
101
233
455Combine this with a previous printing of enum done here
Conversion between enum and string in C++ class header
Code Snippets
const Color Color::blue(0);
const Color Color::green(1);
const Color Color::red(2);
const Color Color::white(3);
const Color Color::yellow(4);
const Color Color::multicolor(5);
const Color Color::hidden(6);#include <iostream>
#include <vector>
#include <iterator>
template<typename T, T... args>
struct EnumIter : public std::iterator<std::input_iterator_tag, T,ptrdiff_t,const T*,const T&>
{
static constexpr T values[] = {args...};
static constexpr std::size_t size = sizeof...(args);
int pos;
EnumIter() // No value is end
: pos(size)
{}
EnumIter(T val)
: pos(std::distance(&values[0], std::find(&values[0], &values[size], val)))
{}
const T& operator*() const {return values[pos];}
EnumIter& operator++() {++pos;return *this;}
EnumIter operator++(int) {EnumIter r(*this);this->operator++();return r;}
bool operator==(EnumIter const& rhs) {return pos == rhs.pos;}
bool operator!=(EnumIter const& rhs) {return pos != rhs.pos;}
};
template<typename T, T... args>
constexpr T EnumIter<T, args...>::values[];enum Ace { One = 101, Two = 233, Three = 455};
typedef struct EnumIter<Ace, One, Two, Three> AceIter;
int main()
{
for(AceIter loop(One); loop != AceIter(); ++loop)
{
std::cout << static_cast<int>(*loop) << "\n";
}
}> g++ -std=c++11 enum.cpp
> ./a.out
101
233
455Context
StackExchange Code Review Q#57626, answer score: 6
Revisions (0)
No revisions yet.