Boost logo

Boost :

Subject: Re: [boost] Enum Conversion
From: Lorenzo Caminiti (lorcaminiti_at_[hidden])
Date: 2012-09-02 16:17:58


On Sun, Sep 2, 2012 at 12:30 PM, Roland Bock <rbock_at_[hidden]> wrote:
> Hi,
>
> In a lot of projects in the company I work for we use Ice middleware
> which allows to define nice interfaces for services. The IDL also allows
> to define enums, but I cannot set specific values for the enum items.
> We also need to store some of these values in databases. We use int to
> represent the enumerations.
>
> Since we might feel the need to add more items to an enum or delete an
> unused one, we cannot just cast enum to int and vice versa when writing
> to or reading from the database. We need methods that translate enum to
> int and back in a stable way that won't change for an individual enum
> item, even if its position in the enum changes.
>
> I found a way to do this, which provides enum<->int and enum<->string.
> It is used like this:
>
> typedef enum
> {
> Alpha,
> Beta,
> Gamma,
> Delta,
> Epsilon
> } Greek;
>
> CREATE_CONVERTER_METHODS(Greek,
> (Alpha, 5),
> (Beta, 3),
> (Gamma, 7),
> (Delta, 1),
> (Epsilon, 6));
>
> std::cout << GreekToString(IntToGreek(1)) << std::endl;
> std::cout << GreekToString(IntToGreek(6)) << std::endl;
> std::cout << GreekToInt(Alpha) << std::endl;
> std::cout << GreekToString(Alpha) << std::endl;
> std::cout << IntToGreek(17) << std::endl;
>
> ------
>
> $ ./a.out
> Delta
> Epsilon
> 5
> Alpha
> terminate called after throwing an instance of 'std::invalid_argument'
> what(): unexpected Greek value
>
>
> My questions are:
>
> a) Is this something that might be interesting for others as well? (Or
> does boost even offer something like that already?)
> b) I'd really like to be able to write this instead:
>
> CREATE_CONVERTER_METHODS(Greek,
> Alpha = 5,
> Beta = 3,
> Gamma = 7,
> Delta = 1,
> Epsilon = 6);
>
> Obviously, if I could use the preprocessor to translate
>
> Alpha = 5 -> (Alpha, 5)
>
> I'd be done. But I have no idea how to do that. Any suggestions?

There's no way you can strip the = symbol with the pp. You can only do:

Alpha = 5 -> (Alpha =, 5)

And that is assuming the number cannot be negative and you don't want
to use the + sign, otherwise you can only do:

Alpha = -5 -> (Alpha = -, 5)
Alpha = +5 -> (Alpha = +, 5)

Depending on the code generated by the macro, this *might* be enough:

Alpha = 5 -> (Alpha =, 5)

That is if the name Alpha can always be use in a context where and
assignment is allowed Alpha =. This includes function parameters with
defaults, variable declarations, expressions, etc. You could even use
a type that has an assignment operation from int and returns itself
when assigned in an expression... For example:

#include <iostream>

struct enum_type
{
    public: struct identity {};
    public: enum_type ( int const& value ) : value_(value) {}
    public: int operator= ( int const& value ) { return value_ = value; }
    public: int operator= ( identity const& ) { return value_; }
    private: int value_;
};

int main ( void )
{
    enum_type Alpha = 5;
    std::cout << (Alpha = enum_type::identity()) << std::endl;
    Alpha = 10;
    std::cout << (Alpha = enum_type::identity()) << std::endl;
    return 0;
}

Note that Alpha is always used as "Alpha =". You can look at the code
generated by your macros, see where you use the token Alpha, and
(creatively) ask yourself if you can replace that with Alpha =
everywhere maybe via some specially defined operator=. I used tricks
like these in Boost.Contract to deal with the = trailing the old-of
variable names.

HTH,
--Lorenzo


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