Boost logo

Boost :

From: Rob Stewart (stewart_at_[hidden])
Date: 2005-06-21 09:46:14


From: Maksym Motornyy <mmotorny_at_[hidden]>
>
> > I think that the names are only "meaningful" if the source language and the
> > application user's language are the same. In general this kind of ability is
> > useful in debugging but in real applications the restraints on identifiers
> > is too limiting (i.e. no punctuation, no accents, no spaces). Far more
> > powerful would be the ability to associate arbitrary data with an enum. This
> > I believe is relatively easy to add to your framework.
>
> Yes, mainly the "meaningful" names can be used for debugging and
> logging. As I wrote in above reply to Sebastien Martel, arbitary data
> can be added by means of enumerator-specific methods.

We write real applications, but we don't need i18n support in
them as they are for internal use. We have a better enum
mechanism, though it relies on macros to generate the necessary
code. Though that mechanism, we frequently turn enumerators into
strings (in both long and short forms) and turn strings into
enumerators.

> > I wish to state for the record, I believe macros should only be used as a
> > last resort.

Here's our syntax:

   SA_BEGIN_ENUM(example)
      enumerator1[ = expression],
      enumerator2[ = expression],
      ...
      enumeratorN[ = expression]
   SA_END_ENUM(example)

   The result is, effectively:

   class example
   {
   public:
      enum value
      {
         enumerator1[ = expression],
         enumerator2[ = expression],
         ...
         enumeratorN[ = expression]
      };
      example()
      {
      }
      example(value value_i)
         : value_(value_i)
      {
      }
      operator value() const
      {
         return value_;
      }
      std::string
      to_string(bool verbose_i = false) const
      {
         return map_s.get_name(value_, verbose_i);
      }
      static example
      from_string(std::string const & name_i, example not_found_i)
      {
         return static_cast<value>(map_s.get_value(name_i, not_found_i));
      }
      static example
      from_string(std::string const & name_i) // throws an exception
      {
         return static_cast<value>(map_s.get_value(name_i));
      }
      static void
      dump()
      {
         map_s.dump();
      }
      // define various operators
   private:
      static ::saol::details::enum_name_mapper map_s;
      value value_;
   public:
      static void
      register_enumerators();
   };
   template <typename Stream>
   Stream &
   operator <<(Stream & stream_io, example value_i)
   {
      return stream_io << value_i.to_string();
   }

To set the names, we use

   SA_BEGIN_ENUMERATOR_REGISTRATION(example)
      SA_REGISTER_ENUMERATOR(enumerator1, "Some long description")
      SA_REGISTER_SIMPLE_ENUMERATOR(enumerator1)
      ...
   SA_END_ENUMERATOR_REGISTRATION(example)

SA_REGISTER_ENUMERATOR registers the enumerator name converted to
a string (preprocessor stringizing) plus the long description as
the non-verbose and verbose forms, respectively.
SA_REGISTER_SIMPLE_ENUMERATOR registers the enumerator name as
both the long and short forms.

> Absolutely agree. If you find "meaningful" names not very useful
> feature, enumerator definition can be done without macros.

We use that regularly. Since the macros generate typesafe code,
we don't find their use problematic.

-- 
Rob Stewart                           stewart_at_[hidden]
Software Engineer                     http://www.sig.com
Susquehanna International Group, LLP  using std::disclaimer;

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk