I wanted to write my own enum class to extend the features of the default enum classes a little bit - like explicit conversions to strings, iterating over the enum, etc. Since I didn't know where to start I asked the mighty Google and found this (fairly old) blog post. I adapted the class to my needs and fixed some compiler issues and came up with the following template
template < typename T >
class Enum {
private:
int m_iValue;
const char* m_sName;
// comparator for the set
struct EnumPtrLess {
bool operator() (const Enum<T>* lhs, const Enum<T>* rhs) {
return lhs->m_iValue < rhs->m_iValue;
}
};
protected:
static std::set<const Enum<T>*, EnumPtrLess> m_sInstances;
explicit Enum(int iVal, const char* sName)
: m_iValue(iVal)
, m_sName(sName)
{
m_sInstances.insert(this); // store the object inside the container
}
public:
typedef std::set<const Enum<T>*, EnumPtrLess> instance_list;
typedef typename instance_list::const_iterator const_iterator;
typedef typename instance_list::size_type size_type;
// convenient conversion operators
operator int() const { return m_iValue; }
explicit operator std::string() const { return m_sName; }
static const Enum<T>* FromInt(int iValue)
{
const_iterator it = std::find_if(m_sInstances.begin(), m_sInstances.end(),
[&](const Enum<T>* e) { return e->m_iValue == iValue; } );
return (it == m_sInstances.end() ? NULL : *it);
}
static size_type Size() { return m_sInstances.size(); }
static const_iterator begin() { return m_sInstances.begin(); }
static const_iterator end() { return m_sInstances.end(); }
};
The problem I have appears when I try to use it. Since m_sInstances
is a static member it needs to be instantiated outside of the template like shown below:
class EDirection : public Enum<EDirection> {
private:
explicit EDirection(int iVal, const char* sName)
: Enum<EDirection>(iVal, sName)
{}
public:
static const EDirection NORTH;
};
template <> Enum<EDirection>::instance_list Enum<EDirection>::m_sInstances;
const EDirection EDirection::NORTH(1, "NORTH");
The specialization of m_sInstances
screws up the linking and let's the build fail:
undefined reference to `Enum::m_sInstances'
Is there any way to avoid that? I can't think of any solution.
Aucun commentaire:
Enregistrer un commentaire