简体   繁体   中英

How can I eliminate the boilerplate of this enum to string mapping code?

I have the following code that not only defines a scoped enumeration, but also has a corresponding mapping with it so I can use the stringized version of its enumerators directly with iostream operator overloads.

enum class ArbitraryNumbers
{
    One,
    Two,
    Three,
    Four,
    Five
};

namespace
{
    using bm_type = boost::bimap<ArbitraryNumbers, std::string>;
    bm_type const g_arbitraryNumbersMap = boost::assign::list_of<bm_type::relation>
        (ArbitraryNumbers::One, "One")
        (ArbitraryNumbers::Two, "Two")
        (ArbitraryNumbers::Three, "Three")
        (ArbitraryNumbers::Four, "Four")
        (ArbitraryNumbers::Five, "Five")
        ;
}

std::ostream& operator<< (std::ostream& os, ArbitraryNumbers number)
{
    auto it = g_arbitraryNumbersMap.left.find(status);
    if (it != g_arbitraryNumbersMap.left.end())
    {
        os << it->second;
    }
    else
    {
        os.setstate(std::ios_base::failbit);
    }

    return os;
}

std::istream& operator>> (std::istream& is, ArbitraryNumbers& number)
{
    std::string number_string;
    is >> number_string;
    auto it = g_arbitraryNumbersMap.right.find(number_string);
    if (it != g_arbitraryNumbersMap.right.end())
    {
        status = it->second;
    }
    else
    {
        is.setstate(std::ios_base::failbit);
    }

    return is;
}

I'd like to wrap this in some sort of reusable fashion. I think the best solution will involve some macros, ideally something like this:

BEGIN_SCOPED_ENUM(ArbitraryNumbers)
    ENUMERATOR(One)
    ENUMERATOR(Two)
    ENUMERATOR(Three)
    ENUMERATOR(Four)
    ENUMERATOR(Five)
END_SCOPED_ENUM()

This is very MFC-like, which is mostly an immediate turn-off for me. But at least this is MUCH easier on the eyes. Another point is that it eliminates boilerplate and is less error prone since the mapping doesn't need to be kept in sync with additions or removals to and from the enumeration itself.

Is there a way I can accomplish this with Boost.Preprocessor, template trickery, or some other useful mechanic?

I did find some ideas online but most of it was hand-spun macros, which I want to avoid. I feel like if I have to go the macro approach that Boost.Preprocessor will be able to do this for me, but it's very complex to use and I'm not sure how to use it to solve this problem. Also most of the solutions I found were really dated, and I want to see if answers would be different with features introduced in STL and core language since between C++03 and C++14.

i'd just write an array:

std::string array[] = {"one", "two", "three"};

I guess the issue is the same as with generating sin-tables automatically.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM