
Hi, I have some code that helps with defining iostream-operators for enums. We use this in our C++<->xml bindings. Basically, it's just two maps (string->enum & enum<-string) and some syntactic sugar. However, I happen to think it is quite neat and so figured it might be useful to other people too. (And it's always nice to give something back :) So, is this something that would fit in boost? Advantages: * Enables lexical_cast on enums. * Pure implementation detail from user-of-enum's perspective. * Very little syntax overhead, inspired by boost::assign. * Works across namespaces & DLLS. * Allows user to define io-ops for "external" enums too. (But the IO-op-macro hs to go into the external namespace.) * Uses pimpl-idiom for faster compilation. * Suitable for header-only version. Issues to work out: * Uses the Loki-singleton to store implementation details. * Initialization is a bit rough. (We get away with it because we have a static "initClass" method for every class. It is a natural place for enumio-setup in our app, but this does not translate to general code well.) * Stores std::strings, although it's almost always constructed from string literals. Wastes a bit of memory for simpler implementation. * EnumIO<E>::The() is globally accessible, so there could be conflicts. (Very low probability though) See below for example & implementation. Comments? Cheers, /Marcus --- user .h ------------------------------------------------ enum Foo { Bar, Baz; } // to export from a win32 dll, add dllimport/export here std::istream& operator>>(std::istream&, Foo& foo); std::ostream& operator<<(std::ostream&, Foo foo); --- user.cpp ------------------------------------------------ #include "user.h" #include <enumio.h> ENUMIO_IMPLEMENT_IOSTREAM_OPS(Foo) // just one way to do it bool init = (::EnumIO<Foo>::the() (Bar, "bar") (Baz, "baz")), true; --- enumio.h ------------------------------------------------ class EnumUtilBase { public: ~ EnumIOBase(); protected: explicit EnumIOBase(const std::type_info& enumType); std::istream & in(std::istream & os, int &value) const; std::ostream & out(std::ostream & os, int value) const; protected: void add(int value, const char* data); private: class Impl; boost::scoped_ptr<Impl> m_i; }; // Helps with serialization (iostream) of enums template<class E> class EnumIO : public EnumIOBase { public: typedef E Enum; EnumIO<E> the() { return ::Loki::SingletonHolder<::EnumIO<E> >::the(); } EnumIO(); EnumIO<E>& operator()(E value, const char* data); std::istream & in(std::istream & is, E & value) const; std::ostream & out(std::ostream & os, E value) const; }; #define ENUMIO_IMPLEMENT_IOSTREAM_OPS(E) \ std::istream& operator>>(std::istream& is, E& value) { \ return ::EnumIO<E>::the().in(is, value); } \ std::ostream& operator>>(std::ostream& os, E value) { \ return ::EnumIO<E>::the().out(os, value); } template<class E> inline EnumIO<E>::EnumIO() : EnumIOBase(typeid(E)) { BOOST_STATIC_ASSERT(sizeof(E) == sizeof(int)); } template<class E> inline EnumIO<E> &EnumIO<E>::operator()(E value, const char* data) { EnumIOBase::add(value, data); return *this; } template<class E> inline std::istream & EnumIO<E>::in(std::istream & is, E & value) const { return EnumIOBase::in(is, (int&) value); } template<class E> inline std::ostream & EnumIO<E>::out(std::ostream& os, E value) const { return EnumIOBase::out(os, value); } --- enumio.cpp ------------------------------------------------ typedef std::map<int, std::string> MapOut; typedef std::map<std::string, int> MapIn; class EnumIOBase::Impl { public: const char* m_typename; ///< is retrieved from typeid(X).name() MapIn m_mapIn; MapOut m_mapOut; }; EnumIOBase::EnumIOBase(const std::type_info& enumType) : m_i(new Impl) { m_i->m_typename = enumType.name(); } EnumIOBase::~EnumIOBase() { } std::istream & EnumIOBase::in(std::istream & is, int &value) const { std::string str; is >> str; if (m_i->m_mapIn.empty()) { MapIn& m = const_cast<MapIn&>(m_i->m_mapIn); for(MapOut::const_iterator i = m_i->m_mapOut.begin(); i != m_i->m_mapOut.end(); ++i) { m.insert(std::make_pair(i->second, i->first)); } } MapIn::const_iterator i = m_i->m_mapIn.find(str); if (i != m_i->m_mapIn.end()) { value = i->second; } else { is.setstate(std::ios::failbit); } return is; } std::ostream & EnumIOBase::out(std::ostream & os, int value) const { const std::string& str = toStr(value); if (!str.empty()) { os << str; } else { os.setstate(std::ios::failbit); } return os; } void EnumIOBase::add(int value, const char* data) { m_i->m_mapOut.insert(std::make_pair(value, data)); }