$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
From: Marcus Lindblom (macke_at_[hidden])
Date: 2007-09-04 03:35:58
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));
}