How to elegantly get the enum code from its string type

Discussion in 'C++' started by thomas, Apr 13, 2010.

  1. thomas

    thomas Guest

    Hi guys,

    I got a problem in practice, and I cannot find a verly elegant
    solution to it.

    ------------------------------------------------------------------------
    enum Type{
    REPLY = 100,
    REP = 1052,
    HAHA = 9523,
    };
    ------------------------------------------------------------------------

    When I open the interface to users for configuration, I would like the
    user to use "REPLY", "REP", "HAHA" like string format because it's
    much easier to recognize and remember.

    But in my program, I need to use the actual code (integral format).

    My solution is to define a map<string, int>, and insert the string and
    integral format pairs into the map for query. But it's really anoying
    and difficult to use, especially when initializing.

    Is there any elegant solution to this problem?

    Thanks in advance.

    Tom
    thomas, Apr 13, 2010
    #1
    1. Advertising

  2. * thomas:
    > Hi guys,
    >
    > I got a problem in practice, and I cannot find a verly elegant
    > solution to it.
    >
    > ------------------------------------------------------------------------
    > enum Type{
    > REPLY = 100,
    > REP = 1052,
    > HAHA = 9523,
    > };


    Don't use all uppercase for the identifiers (this advice is in most serious
    FAQs, including this group's FAQ and Bjarne's mini-FAQ).

    Reserve all uppercase for macros, to minimize macro name collisions.

    Also, a comma after the last item is accepted by some compilers but relative to
    C++98 is a non-standard language extension, so if you desire portability, don't.


    > ------------------------------------------------------------------------
    >
    > When I open the interface to users for configuration, I would like the
    > user to use "REPLY", "REP", "HAHA" like string format because it's
    > much easier to recognize and remember.


    Yep.


    > But in my program, I need to use the actual code (integral format).
    >
    > My solution is to define a map<string, int>, and insert the string and
    > integral format pairs into the map for query.


    Use a map<string, Type>.



    > But it's really anoying
    > and difficult to use, especially when initializing.


    Huh?


    > Is there any elegant solution to this problem?


    <code>
    #include <string>
    #include <stdexcept>
    #include <stddef.h>

    typedef ptrdiff_t Size;

    template< typename T, Size N >
    Size size( T (&)[N] ) { return N; }

    enum SomeEnum { reply = 100, rep = 1052, haha = 9523 };

    SomeEnum someEnumFrom( std::string const& name )
    {
    typedef std::pair< char const*, SomeEnum > Pair;
    static Pair const values[] =
    {
    Pair( "reply", reply ), Pair( "rep", rep ), Pair( "haha", haha )
    };

    for( int i = 0; i < size( values ); ++i )
    {
    if( values.first == name ) { return values.second; }
    }
    throw std::runtime_error( "someEnumFrom: no such name" );
    }

    #include <iostream>
    int main()
    {
    SomeEnum const e = someEnumFrom( "haha" );
    std::cout << e << std::endl;
    }
    </code>


    Cheers & hth.,

    - Alf
    Alf P. Steinbach, Apr 13, 2010
    #2
    1. Advertising

  3. * Leigh Johnston:
    >
    >
    > "Alf P. Steinbach" <> wrote in message
    > news:hq1i2i$7ra$-september.org...
    >> typedef ptrdiff_t Size;

    >
    > So you like arrays with a negative number of elements?


    Translated: you don't understand the above and you're wondering why.

    The main reason is that dealing with unsigned types for anything other than bit
    manipulation, leads to lots of possible bugs due to implicit promotion. For
    example, if v is a std::vector, then v.size() > -1 yields false. However, with
    the definition above, Size( v.size() ) > -1 yields true (correct).

    Even in the cases where you know that the code is safe, such as the comparision
    in the loop below, the compiler doesn't know and may issue some diagnostic. You
    don't want that diagnostic. At least if you take in pride in your work.


    >> for( int i = 0; i < size( values ); ++i )
    >> {
    >> if( values.first == name ) { return values.second; }
    >> }
    >> throw std::runtime_error( "someEnumFrom: no such name" );
    >> }

    >
    > This is fine if you only have a few items however it doesn't scale
    > (linear complexity) so for the more general case a map might be superior.


    No. :)


    Cheers & hth.,

    - Alf
    Alf P. Steinbach, Apr 13, 2010
    #3
  4. * Leigh Johnston:
    >
    >
    > "Alf P. Steinbach" <> wrote in message
    > news:hq1qsj$3pq$-september.org...
    >> * Leigh Johnston:
    >>>
    >>>
    >>> "Alf P. Steinbach" <> wrote in message
    >>> news:hq1i2i$7ra$-september.org...
    >>>> typedef ptrdiff_t Size;
    >>>
    >>> So you like arrays with a negative number of elements?

    >>
    >> Translated: you don't understand the above and you're wondering why.
    >>
    >> The main reason is that dealing with unsigned types for anything other
    >> than bit manipulation, leads to lots of possible bugs due to implicit
    >> promotion. For example, if v is a std::vector, then v.size() > -1
    >> yields false. However, with the definition above, Size( v.size() ) >
    >> -1 yields true (correct).
    >>
    >> Even in the cases where you know that the code is safe, such as the
    >> comparision in the loop below, the compiler doesn't know and may issue
    >> some diagnostic. You don't want that diagnostic. At least if you take
    >> in pride in your work.
    >>
    >>
    >>>> for( int i = 0; i < size( values ); ++i )
    >>>> {
    >>>> if( values.first == name ) { return values.second; }
    >>>> }
    >>>> throw std::runtime_error( "someEnumFrom: no such name" );
    >>>> }
    >>>
    >>> This is fine if you only have a few items however it doesn't scale
    >>> (linear complexity) so for the more general case a map might be
    >>> superior.

    >>
    >> No. :)
    >>
    >>
    >> Cheers & hth.,
    >>
    >> - Alf

    >
    > More bullshit from Alf what a surprise.


    Perhaps you could be a litte more specific about what you don't understand,
    Leigh, and perhaps express your lack of understanding in a less emotional way.

    All this invective that you spout makes it difficult to help you.


    > Use ptrdiff_t *or* size_t for subscripting, use size_t for sizes. If
    > you look at the standard you will find the following:
    >
    > size_type can represent any non-negative value of difference_type
    >
    > std::vector<T>::eek:perator[](size_type)
    >
    > you will not find:
    >
    > std::vector<T>::eek:perator[](difference_type)
    >
    > and as far as your rubbish solution is concerned:
    >
    > typedef std::size_t Size;
    >
    > for( Size i = 0; i < size( values ); ++i )
    >
    > Use signed where negative values make sense. Use unsigned where
    > negative values do not make sense.


    I'm sorry but while you have the facts right, the conclusions that you draw do
    not follow from those facts. The matter has been discussed in this group before,
    extensively. You can look up those discussions to learn about the issues, but
    essentially, the advice that you give makes sense in Pascal, which enforces the
    indicated ranges and where using such ranges therefore adds safety and clarity,
    but not in C++, which does not enforce the ranges and where using such ranges
    reduces safety and reduces clarity (both directly and by generally yielding more
    verbose code). I.e., your advice is nothing but a mindless transfer of idiomatic
    style from a language where it makes sense, to a language where it has mostly
    negative consequences. The modern consensus is that the standard got this mainly
    wrong, although if you check out the discussions you'll find that there is an
    issue for embedded systems and for some now no longer relevant architectures.


    Cheers & hth.,

    - Alf
    Alf P. Steinbach, Apr 13, 2010
    #4
  5. * Leigh Johnston:
    >
    >
    > "Alf P. Steinbach" <> wrote in message
    > news:hq1u1o$rmi$-september.org...
    >> I'm sorry but while you have the facts right, the conclusions that you
    >> draw do not follow from those facts. The matter has been discussed in
    >> this group before, extensively. You can look up those discussions to
    >> learn about the issues, but essentially, the advice that you give
    >> makes sense in Pascal, which enforces the indicated ranges and where
    >> using such ranges therefore adds safety and clarity, but not in C++,
    >> which does not enforce the ranges and where using such ranges reduces
    >> safety and reduces clarity (both directly and by generally yielding
    >> more verbose code). I.e., your advice is nothing but a mindless
    >> transfer of idiomatic style from a language where it makes sense, to a
    >> language where it has mostly negative consequences. The modern
    >> consensus is that the standard got this mainly wrong, although if you
    >> check out the discussions you'll find that there is an issue for
    >> embedded systems and for some now no longer relevant architectures.
    >>
    >>
    >> Cheers & hth.,
    >>
    >> - Alf

    >
    > More bullshit Alf, sorry. The basic fact that *you* do not seem to
    > understand is:
    >
    > Eschewing a language feature because you can create bugs with it is a
    > nonsense as you can create bugs with any language feature. Bugs are
    > inevitable. Bug fixes are inevitable.
    >
    > The past history of retarded posts to a particularly flaky Usenet
    > newsgroup a language standard does not make.
    >
    > Use a signed integral type when negative values make sense. Use an
    > unsigned integral type when negative values do not make sense. When the
    > two collide convert as necessary and if you cannot convert because a
    > particular value is out of the range of a particular type then you have
    > larger problems (i.e. use a larger type if available).


    Well, you do not seem to register any of the technical points, and you just
    repeatedly assert your earlier stance with, as before, invective. That's not
    discussion, it's not debate, it's not knowledge seeking. I give up, sorry.


    Cheers & again, sorry,

    - Alf
    Alf P. Steinbach, Apr 13, 2010
    #5
  6. On Apr 13, 10:52 am, "Leigh Johnston" <> wrote:
    > I have no problems mixing signed and unsigned integer logic in my code.


    Which you then in the very next sentence contradict:

    > Yes I have occasionally created bugs when I mix the two and I usually
    > find said bugs fairly quickly and fix them (they are not hard to fix).


    How quickly you detect problems does not change the fact that
    you do have problems. In addition, what is the cost of finding
    those bugs? What is the cost of the fix in terms of time and
    also code ugglification?

    You are a smart guy working on toys so finding and fixing such
    bugs is "no big deal". But in other contexts it can be costly
    and such costs can far outweigh any philosophical benefit to
    using unsigned types in notorious "problem" spots.

    > I have been coding in C++ since 1993 so I am not the total
    > newbie that you seem to think I am.


    Personally I'm doubtful anyone thinks you are a "total newbie".
    And I think you are very smart (partly because "Dune" is one of
    your favorite movies). Rather, I think the problem rests with
    you assuming the rest of us are "full of shit" and thus are
    FAR to quick to hyperactively attack instead of understanding.

    It is obvious that you know C++ /the language/ well. However,
    what is not so clear is how well you know C++ /the practice/.
    Often what I and others are discussing here is the effective
    use of C++ as a software development tool in a larger team.
    Honestly, from the things you say and your attitude, I doubt
    you have much experience with said practice. Because some of
    the good advice you rail against is actually quite "obvious"
    to anyone who has worked in a largish team and carefully
    observed what went wrong and right.

    > Debate? I am simply expressing an opinion which happens to
    > be at odds with some divine knowledge that you are asserting
    > is true.


    It isn't "divine". It is observed from experience and/or
    derived from sometimes quite detailed debates. The problem
    is you simply refuse to educate yourself on those technical
    debates nor to accept the limitations of your experience.

    KHD
    Keith H Duggar, Apr 13, 2010
    #6
  7. On Apr 13, 11:56 am, "Leigh Johnston" <> wrote:
    > "Keith H Duggar" <> wrote in messagenews:...
    >
    >
    >
    > > It isn't "divine". It is observed from experience and/or
    > > derived from sometimes quite detailed debates. The problem
    > > is you simply refuse to educate yourself on those technical
    > > debates nor to accept the limitations of your experience.

    >
    > Consider this:
    >
    > 1) std::vector<T>::eek:perator[](size_type) is widely used (in practice not
    > theory)
    > 2) std::vector<T>::size_type is a typedef of std::allocator<T>::size_type
    > 3) std::allocator<T>::size_type is a typedef of std::size_t
    > 4) std::size_t is an unsigned integral type
    >
    > ergo
    >
    > unsigned integral types are widely used in practice (not theory).


    You already caught your own error here in another post. And
    regardless we all know that commonality is not a measure of
    excellence.

    > As far as *my* practical experience is concerned all of my programming jobs
    > to date have involved C++ development in both large and small teams.


    If that is the case and if (a big IF) you, as I wrote, "carefully
    observed what went wrong and right", then some of your outbursts
    are truly mystifying. Unfortunately, since well reasoned focused
    arguments are not springing forth (on this topic) from the Divine
    "It's Fine" Leigh, it's excessively painful to explore your
    opinions futher.

    > I don't attach much value to the debates that occur in this newsgroup
    > primarily because it is not moderated and the debates themselves are more
    > often than not simply pissing contests. :)


    1) Why is this a problem? Are you incapable of applying your
    very own "think for yourself" mantra to filter out the pissing
    and focus on technical facts and arguments?

    2) Alf did not specify /this/ forum. The discussions have
    taken place in many forums including (but certainly not
    limited to) for example the moderated C++ usenet group:

    http://groups.google.com/group/comp...arch?group=comp.lang.c++.moderated&q=unsigned

    where you can find debates having /hundreds/ of moderated
    posts arguing the topic. Do you have anything /new/ to add
    to that well trodden territory?? So far the answer is no.

    KHD
    Keith H Duggar, Apr 13, 2010
    #7
  8. * Leigh Johnston:
    >
    > I don't attach much value to the debates that occur in this newsgroup
    > primarily because it is not moderated and the debates themselves are
    > more often than not simply pissing contests. :)


    As I read it (I may be wrong of course) there are two main positions/opinions
    communicated by that statement. The first, that moderation helps directly to
    ensure technical accuracy. And the second, that moderation helps indirectly to
    ensure technical accuracy by preventing "pissing contests".

    Both these positions/opinions are incorrect for the C++ Usenet groups; the
    moderated sister groups just have much less noise, possibly a higher percentage
    of expert posters (e.g. it's many many years since I've seen Andrei posting in
    this group, but he does post in the moderated groups), and longer posting delay.

    If I should post an article that was wrong in almost every technical aspect, to
    [comp.lang.c++.moderated], then the moderators would have to accept it if it was
    on-topic, and the criteria for topicality there are, essentially, that there is
    at least some nugget of C++ related content interspersed in the miles long
    discussion of WWII foo fighter sightings, and that it's not overly trivial.

    Also, pissing contests do occur also in the moderated group, although not as
    frequently, and utilizing more advanced rhetoric than simple name-calling.

    It's very difficult for the moderators to clamp down on that, because usually
    there is at least one way to interpret such an article where it's apparently all
    technical and to the point, while there's also at least one interpretation, say,
    suggested by the selection of examples, that is much less, uh, nice. For
    example, I believe in English there is a saying like "Damning with faint
    praise". That's a technique where apparently something is said to be good, but
    where compared to what would be said if it was really good, it's clear to anyone
    who can read between the lines that it's being put down. This kind of subtlety,
    and other kinds, do occur. Happily it's more difficult to do, and so in spite of
    the difficulties of clamping down on such, the s/n ratio is kept pretty high.

    In short, do not assume that an article in [comp.lang.c++.moderated] or
    [comp.std.c++] is necessarily more likely to be correct than an article here.
    And that holds even if you do not agree with or believe my explanation above.
    For example, in the last years most articles in [comp.lang.c++.moderated],
    including yours, have been processed by me. Since in your opinion I'm in the
    habit of posting bullshit, I would presumably not be qualified to evaluate
    correctness, and so technically incorrect and misleading articles would slip
    through even if we did try to stop them. But we don't.

    The moderators do not judge correctness; they only judge topicality and noise.


    Cheers & hth.,

    - Alf
    Alf P. Steinbach, Apr 13, 2010
    #8
  9. * Leigh Johnston:
    >
    > "Alf P. Steinbach" <> wrote in message
    > news:hq26c4$snn$-september.org...
    >> In short, do not assume that an article in [comp.lang.c++.moderated]
    >> or [comp.std.c++] is necessarily more likely to be correct than an
    >> article here. And that holds even if you do not agree with or believe
    >> my explanation above. For example, in the last years most articles in
    >> [comp.lang.c++.moderated], including yours, have been processed by me.
    >> Since in your opinion I'm in the habit of posting bullshit, I would
    >> presumably not be qualified to evaluate correctness, and so
    >> technically incorrect and misleading articles would slip through even
    >> if we did try to stop them. But we don't.
    >>

    >
    > Yes that is a good pwn (you being a moderator).


    I'm sorry, I didn't mean to pwn you, just to supply clearly reliable
    information. Please do not make such assumptions. This group normally does not
    work in an adversarial way; it's more about learning and fleshing out points of
    view, civilized discourse, at least when it's working without provocation.

    Also, I'm sorry, I didn't mean to put myself forward. Neither I nor other
    moderators make any big point about that. Other clc++m moderators posting here
    regularly currently include James Kanze and Victor Bazarov.


    > Well done, keep up the good work. :)


    Thanks.


    Cheers,

    - Alf
    Alf P. Steinbach, Apr 13, 2010
    #9
  10. thomas

    werasm Guest

    On Apr 13, 11:53 am, thomas <> wrote:
    > Hi guys,
    >
    >       I got a problem in practice, and I cannot find a verly elegant
    > solution to it.
    >
    > ------------------------------------------------------------------------
    > enum  Type{
    >        REPLY = 100,
    >        REP    = 1052,
    >        HAHA  = 9523,};
    >
    > ------------------------------------------------------------------------
    >
    > When I open the interface to users for configuration, I would like the
    > user to use "REPLY", "REP", "HAHA" like string format because it's
    > much easier to recognize and remember.
    >
    > But in my program, I need to use the actual code (integral format).
    >
    > My solution is to define a map<string, int>, and insert the string and
    > integral format pairs into the map for query. But it's really anoying
    > and difficult to use, especially when initializing.
    >
    > Is there any elegant solution to this problem?
    >
    > Thanks in advance.
    >
    > Tom


    boost::lexical cast uses operator >> to do conversions. By
    overloading operators << and >> for a type T lexical
    cast can easily be used:

    This is more or less what I did in the code here below. I had to
    subclass and provide the map (makeValueMap) as mentioned
    by another poster. Hope it makes sense. Werner

    class T_AsEnumBase
    {
    protected:
    struct ECantConvert{};
    };

    // Provides the ability to be lexically casted (by operator >>).
    // It is typically used to convert a string value representing type T
    in a
    // configuration file to its representing enumerated type.
    // It is automatically convertible to the associated enumerated type.
    // Notes:
    // 1) Inherits from T_AsEnumBase - merely to share the exception type.
    // 2) Classes deriving from this should override method "doConvert".
    This method
    // may only throw exception ECantConvert. Its purpose is to convert
    the value
    // to the representing enumerated type.
    // 4.1) StringAsEnum<EnumT> : Derive from to convert string values to
    EnumT.
    // 4.2) IntAsEnum<EnumT> : Derive from to convert integral values to
    EnumT.
    // 5) See below for a typical example of derived implementation /
    Usage.
    // 6) If one does not overload operator << for the derived type (in
    the same
    // namespace!!!), std::eek:perator << (std::eek:stream&, int ) will be used
    (due to
    // conversion operator operator EnumT()).

    template <class T, class EnumT>
    class T_AsEnum : public T_AsEnumBase
    {
    public:
    T_AsEnum(): value_(){ }
    EnumT get() const{ return value_; }
    operator EnumT() const{ return get(); }
    bool set( const T& value )
    {
    try
    {
    value_ = doConvert( value );
    return true;
    }
    catch( ECantConvert e )
    {
    return false;
    }
    }
    private:
    //Note:
    //- Throw ECantConvert int the event of a conversion failure.
    //- All other exceptions are uncaught/unexpected.
    virtual EnumT doConvert( const T& inVal ) const /
    *throw(ECantConvert)*/ = 0;
    EnumT value_;
    };
    template <class T, class EnumT>
    std::istream& operator >> ( std::istream& input, T_AsEnum<T,EnumT>&
    result )
    {
    T inVal;
    if( input >> inVal )
    {
    if( result.set( inVal ) == false )
    {
    input.setstate( std::ios::failbit );
    }
    }
    return input;
    }

    //Convenience classes to derive from.
    template <class EnumT>
    class IntAsEnum : public T_AsEnum<int, EnumT>{ };

    template <class EnumT>
    class StringAsEnum : public T_AsEnum<std::string, EnumT>{ };

    // Description:
    // This class uses an STL compliant map to convert from a string value
    // to the corresponding enumerated value. Be default std::map is used.
    // Note:
    // 1) It is necessary to provide an implementation for function
    makeValueMap.
    // For an STL map (default) the implementation declaration will look
    as follows:
    // const std::map<std::string,EnumT>& makeValueMap() const;

    template <class EnumT, class MapT = std::map<std::string, EnumT> >
    class StringAsMappedEnum : public StringAsEnum<EnumT>
    {
    private:
    virtual EnumT doConvert( const std::string& inVal ) const
    {
    static const MapT& valueMap = makeValueMap();

    typename MapT::const_iterator pos = valueMap.find( inVal );
    if( pos != valueMap.end() )
    {
    return pos->second;
    }
    throw T_AsEnumBase::ECantConvert();
    }
    virtual const MapT& makeValueMap() const = 0;
    };
    werasm, Apr 13, 2010
    #10
  11. thomas

    tonydee Guest

    On Apr 13, 6:53 pm, thomas <> wrote:
    > enum  Type{
    >        REPLY = 100,
    >        REP    = 1052,
    >        HAHA  = 9523,};
    >
    > When I open the interface to users for configuration, I would like the
    > user to use "REPLY", "REP", "HAHA" like string format because it's
    > much easier to recognize and remember.
    >
    > But in my program, I need to use the actual code (integral format).
    >
    > My solution is to define a map<string, int>, and insert the string and
    > integral format pairs into the map for query. But it's really anoying
    > and difficult to use, especially when initializing.
    >
    > Is there any elegant solution to this problem?


    Not that I'm aware of. A simplified version of my preferred approach
    follows (hacked up in half an hour, so expect to need a tweak or two)
    - there's a bit of stuff you can throw in a header, then the usage is:

    BENUM(Identifier, value-list...)

    To create "class Identifier" implicitly convertible to/from an enum
    with the listed values, with an operator<< provided. operator>> can
    be trivially added.

    The downside is that the identifier<->value associations are created
    at run-time on first use, so there's a slight performance impact. As
    presented here, I'm lazy and create strings willy-nilly, though it's
    trivial to write and apply a "read-only string class" based around a
    const char* and size_t.

    A totally over-engineered version supporting streaming in and out,
    custom containers for value/identifier association, markup for
    implicit values and bit flags etc. is available in benum_v1.zip at the
    Boost Vault, though in hindsight I feel I should have focused on
    simpler use cases. Should finish it off, but nobody's asking me to
    and I'm lazy.

    Cheers,
    Tony

    // benum support code... (put in a header)

    #include <iostream>
    #include <string>
    #include <map>

    namespace Benum
    {
    struct Meta
    {
    Meta(const char* p, int* p_values)
    {
    while (*p)
    {
    if (isalnum(*p) || *p == '_')
    {
    const char* p_from = p;
    while (isalnum(*p) || *p == '_')
    ++p;
    std::string idn = std::string(p_from, p - p_from);
    // std::cout << "meta " << idn << '=' << *p_values
    << '\n';
    int_to_string_[*p_values] = idn;
    string_to_int_[idn] = *p_values;
    ++p_values;
    }
    else if (*p == '=')
    while (*p && *p != ',')
    ++p;
    else
    ++p;
    }
    }
    std::eek:stream& out(std::eek:stream& os, int i) const
    {
    Int_To_String::const_iterator it = int_to_string_.find(i);
    if (it != int_to_string_.end())
    return os << it->second;
    else
    return os << "<unmatched enum " << i << '>';
    }
    typedef std::map<int, std::string> Int_To_String;
    std::map<int, std::string> int_to_string_;
    std::map<std::string, int> string_to_int_;
    };

    template <typename T>
    struct Incrementing
    {
    Incrementing(int n) : n_(n) { s_next_implicit_ = n + 1; }
    Incrementing() : n_(s_next_implicit_++) { }
    operator int() const { return n_; }
    int n_;
    static int s_next_implicit_;
    };

    template <typename T>
    int Incrementing<T>::s_next_implicit_;
    }

    #define BENUM(IDN, ...) \
    enum IDN ## _Enum { __VA_ARGS__ }; \
    class IDN { \
    typedef IDN ## _Enum Enum; \
    IDN(Enum e) : e_(e) { } \
    IDN& operator=(Enum e) { e_ = e; return *this; } \
    operator Enum() const { return e_; } \
    friend std::eek:stream& operator<<(std::eek:stream& os, Enum e) { \
    return IDN::meta().out(os, e); \
    } \
    static const Benum::Meta& meta() { \
    static Benum::Incrementing<IDN> __VA_ARGS__; \
    static int values[] = { __VA_ARGS__ }; \
    static Benum::Meta m(#__VA_ARGS__, values); \
    return m; \
    } \
    Enum e_; \
    };

    // benum example usage...

    BENUM(Type, One = 1, Two = 2, Three = 3, Four = 4, Whats_Next);

    int main()
    {
    std::cout << One << ' ' << Two << ' ' << Three << ' ' <<
    Whats_Next << '\n';
    }
    tonydee, Apr 14, 2010
    #11
  12. Leigh Johnston wrote:
    >
    >
    > "Alf P. Steinbach" <> wrote in message
    > news:hq1i2i$7ra$-september.org...
    >> typedef ptrdiff_t Size;

    >
    > So you like arrays with a negative number of elements?


    Agree. I would call it a logical error.
    Alf, why did you use int here?

    >
    >>
    >> for( int i = 0; i < size( values ); ++i )
    >> {
    >> if( values.first == name ) { return values.second; }
    >> }
    >> throw std::runtime_error( "someEnumFrom: no such name" );
    >> }

    >
    > This is fine if you only have a few items however it doesn't scale
    > (linear complexity) so for the more general case a map might be superior.


    Also agree. Just one question : do you handle a case when someone pass a
    bogus value. Like in the above case: static_cast< Type >(1234) ?

    If yes, how?
    Vladimir Jovic, Apr 14, 2010
    #12
  13. * Vladimir Jovic:
    > Leigh Johnston wrote:
    >>
    >>
    >> "Alf P. Steinbach" <> wrote in message
    >> news:hq1i2i$7ra$-september.org...
    >>> typedef ptrdiff_t Size;

    >>
    >> So you like arrays with a negative number of elements?

    >
    > Agree. I would call it a logical error.


    A possible explanation is that you think of 'unsigned' as indicating a value range.

    It doesn't.

    It has a possible number range, but like 'int' it doesn't indicate a range; if
    anything it indicates modular arithmetic, which is not usually intended.


    > Alf, why did you use int here?


    'int' is the natural integer type in C++, and has few problems.

    An unsigned type has many problems.

    I could have added work in order to ask for problems, but is that smart?


    >>> for( int i = 0; i < size( values ); ++i )
    >>> {
    >>> if( values.first == name ) { return values.second; }
    >>> }
    >>> throw std::runtime_error( "someEnumFrom: no such name" );
    >>> }

    >>
    >> This is fine if you only have a few items however it doesn't scale
    >> (linear complexity) so for the more general case a map might be superior.

    >
    > Also agree


    At a guess you'd need at least some thousand enum values in order for a std::map
    to perform better. In that case you'd use some system instead of mapping strings
    to individual values (and you'd not use an enum). And even with the horror of
    thousands of non-systematic enum values a std::map would be a premature
    optimization.



    Cheers & hth.,

    - Alf
    Alf P. Steinbach, Apr 14, 2010
    #13
  14. * Leigh Johnston:
    >
    >
    > "Alf P. Steinbach" <> wrote in message
    > news:hq4dsb$96t$-september.org...
    >>
    >> An unsigned type has many problems.
    >>
    >> I could have added work in order to ask for problems, but is that smart?
    >>

    >
    > There is nothing wrong with unsigned integers, they are a perfectly fine
    > language feature.


    Literally correct.

    My statement was made in context.

    To take another example, there's nothing wrong with vanilla ice cream.


    Cheers & hth.,

    - Alf
    Alf P. Steinbach, Apr 14, 2010
    #14
  15. thomas

    Kai-Uwe Bux Guest

    Leigh Johnston wrote:

    >
    >
    > "Alf P. Steinbach" <> wrote in message
    > news:hq4dsb$96t$-september.org...
    >>
    >> An unsigned type has many problems.
    >>
    >> I could have added work in order to ask for problems, but is that smart?
    >>

    >
    > There is nothing wrong with unsigned integers, they are a perfectly fine
    > language feature.


    The unsigned types are indeed a perfectly fine language feature; and there
    are contexts where you absolutely would want to have them. What causes
    trouble, every once in a while, are the rules for conversion and promotion.
    It is with those in mind that one has to make the call whether a variable or
    a return type should be signed or unsigned. Opinions differ on what is
    advantageous in which context. Probably, a lot depends on the local culture:
    code should reflect intent, and different shops can use the signed/unsigned
    distinction as slightly different markers.


    Best

    Kai-Uwe Bux
    Kai-Uwe Bux, Apr 14, 2010
    #15
  16. * Leigh Johnston:
    >
    >
    > "Kai-Uwe Bux" <> wrote in message
    > news:hq4f9d$9qf$...
    >>
    >> The unsigned types are indeed a perfectly fine language feature; and
    >> there
    >> are contexts where you absolutely would want to have them. What causes
    >> trouble, every once in a while, are the rules for conversion and
    >> promotion.
    >> It is with those in mind that one has to make the call whether a
    >> variable or
    >> a return type should be signed or unsigned. Opinions differ on what is
    >> advantageous in which context. Probably, a lot depends on the local
    >> culture:
    >> code should reflect intent, and different shops can use the
    >> signed/unsigned
    >> distinction as slightly different markers.
    >>

    >
    > Yes code should reflect intent and my use of unsigned integral types
    > reflect the fact that I am using values that only make sense when
    > positive. If I have values which can be positive or negative then I
    > will use a signed integral type.
    >
    > Alf's assertion that unsigned types indicate "modular arithmetic" is a
    > nonsense as sizeof(T) does not indicate "modular arithmetic" and the
    > type of the sizeof operator is std::size_t which is an unsigned integral
    > type.


    The standard guarantees modular arithmetic for an unsigned integral type.

    Thus, your argument is one of arbitrary and wilfully uninformed choice: you're
    choosing types for what they indicate to you, and you're choosing what they
    indicate to you by emhasizing their names and maintaining that their
    functionality can't be indicating anything, that considering functionality is
    nonsense, and you're maintaining that this choice is inherent in the language.

    To me that is nonsense, so we disagree on the notion of "sense".


    > std::size_t is used extensively in the real world so unsigned
    > types are also used extensively in the real world and not just in
    > "modular arithmetic" contexts.


    That is correct. But to argue that it's good, a practice to emulate, you'd have
    to present some argument. So far you have to refused to consider any argument.


    Cheers & hth.,

    - Alf
    Alf P. Steinbach, Apr 14, 2010
    #16
  17. On Apr 14, 9:27 am, "Leigh Johnston" <> wrote:
    > "Kai-Uwe Bux" <> wrote in message
    > > The unsigned types are indeed a perfectly fine language feature; and there
    > > are contexts where you absolutely would want to have them. What causes
    > > trouble, every once in a while, are the rules for conversion and
    > > promotion.
    > > It is with those in mind that one has to make the call whether a variable
    > > or
    > > a return type should be signed or unsigned. Opinions differ on what is
    > > advantageous in which context. Probably, a lot depends on the local
    > > culture:
    > > code should reflect intent, and different shops can use the
    > > signed/unsigned
    > > distinction as slightly different markers.

    >
    > Yes code should reflect intent and my use of unsigned integral types reflect
    > the fact that I am using values that only make sense when positive. If I
    > have values which can be positive or negative then I will use a signed
    > integral type.
    >
    > Alf's assertion that unsigned types indicate "modular arithmetic" is a
    > nonsense as sizeof(T) does not indicate "modular arithmetic" and the type of


    unsigned types in C++ /ARE/ modular arithmetic. This is defined
    by the standard. As to whether they "indicate", well who knows?
    Indicate to whom? In what context?

    "indicate" aside, it is fact that they are modular arithmetic
    and as such "positive" and "negative" lose distinction because
    of modular congruence. And that when combined with C++ implicit
    conversion rules is the heart of the problem.

    Anyhow, have you even bothered to READ the moderated debates
    on this topic? Or do you simply refuse to educate yourself any
    further and just want to prance around ranting your vociferous
    opinion? Ask yourself (and I literally mean only yourself) what
    is your goal here in clc++ and are you achieving that goal?

    > the sizeof operator is std::size_t which is an unsigned integral type.
    > std::size_t is used extensively in the real world so unsigned types are also
    > used extensively in the real world and not just in "modular arithmetic"
    > contexts.


    What exactly do you think this "extensive use" demonstrates?
    Did you miss Alf's claim that the "consensus" now is that the
    standard got this wrong?

    Do you have ANYTHING, anything NEW at all to offer us on this
    topic? So far you have nothing except tired old rants, a broken
    noisy recording.

    > std::allocator<T>::size_type is a typedef of std::size_t which is an
    > unsigned integral type.
    >
    > As I mentioned elsewhere in this thread the following is perfectly fine:


    LOL "perfectly fine". Divine "It's Fine" Leigh is indeed
    a perfect moniker for you.

    KHD
    Keith H Duggar, Apr 14, 2010
    #17
  18. * Leigh Johnston:
    >
    >
    > "Alf P. Steinbach" <> wrote in message
    > news:hq4gun$vjb$-september.org...
    >>
    >> The standard guarantees modular arithmetic for an unsigned integral type.

    >
    > I didn't claim otherwise


    You did: <<that unsigned types indicate "modular arithmetic" is a nonsense>>.


    >, modular arithmetic is a property of unsigned
    > integral types yes but that does not mean that the only use of unsigned
    > integral types is for performing modular arithmetic.


    That's correct, yes.

    It seems that this a strawman argument.

    That is, arguing against a position not held or expressed by the one you're
    arguing against.


    >> Thus, your argument is one of arbitrary and wilfully uninformed
    >> choice: you're choosing types for what they indicate to you, and
    >> you're choosing what they indicate to you by emhasizing their names
    >> and maintaining that their functionality can't be indicating anything,
    >> that considering functionality is nonsense, and you're maintaining
    >> that this choice is inherent in the language.

    >
    > Rubbish, I use both a sensible name for a variable in addition to a
    > sensible type. Unsigned integral types make sense when it makes no
    > sense to have negative values.


    Perhaps you could expand on why you think that that makes sense: practical
    advantages and/or disadvantages of using a signed type?


    > Negative "sizes" are unusual so it makes
    > sense to use an unsigned integral type to represent sizes and
    > std::size_t is a good example of this (clue *is* in the name).


    The arguments presented against 'unsigned' size types have not been related to
    any possibility of negative sizes.

    It may be that this is your criterion for using an unsigned type, that if no
    negative values should occur, then choose an unsigned type.

    But if so then the questions are, (1) what advantages do you think that has,
    and (2) have you at all considered the disadvantages?

    The problems lie in the usage context, where negative numbers can occur.

    You have admitted to encountering such problems.


    >>> std::size_t is used extensively in the real world so unsigned types
    >>> are also used extensively in the real world and not just in "modular
    >>> arithmetic" contexts.

    >>
    >> That is correct. But to argue that it's good, a practice to emulate,
    >> you'd have to present some argument. So far you have to refused to
    >> consider any argument.
    >>

    >
    > I need present no further argument as (to me) the benefits of using
    > correct types for abstractions is self evident and exist in the C++
    > standard and emulation of such practices is a good thing.


    Oh my.


    > std::vector<T>::eek:perator[](size_type index) is one such example, index
    > should never be negative so size_type should be an unsigned integral type.


    I hear you, you believe that, but why do you believe that?


    Cheers & hth.,

    - Alf
    Alf P. Steinbach, Apr 14, 2010
    #18
  19. Alf P. Steinbach wrote:
    > * Vladimir Jovic:
    >> Leigh Johnston wrote:
    >>>
    >>>
    >>> "Alf P. Steinbach" <> wrote in message
    >>> news:hq1i2i$7ra$-september.org...
    >>>> typedef ptrdiff_t Size;
    >>>
    >>> So you like arrays with a negative number of elements?

    >>
    >> Agree. I would call it a logical error.

    >
    > A possible explanation is that you think of 'unsigned' as indicating a
    > value range.
    >
    > It doesn't.
    >
    > It has a possible number range, but like 'int' it doesn't indicate a
    > range; if anything it indicates modular arithmetic, which is not usually
    > intended.
    >


    Generally speaking, it a number can not have negative numbers, it
    shouldn't be signed (as Leigh said in other tread). You can introduce
    bugs by using signed int, if you forget to check if the value is negative.

    >
    >> Alf, why did you use int here?

    >
    > 'int' is the natural integer type in C++, and has few problems.
    >
    > An unsigned type has many problems.
    >
    > I could have added work in order to ask for problems, but is that smart?
    >


    Off course not.

    In this specific example, it is irrelevant whether the Size type is
    signed or unsigned. I fail to see how could you possible introduce bugs
    by choosing the unsigned int in this case.

    Where can I read about problems of the unsigned types?

    >
    >>>> for( int i = 0; i < size( values ); ++i )
    >>>> {
    >>>> if( values.first == name ) { return values.second; }
    >>>> }
    >>>> throw std::runtime_error( "someEnumFrom: no such name" );
    >>>> }
    >>>
    >>> This is fine if you only have a few items however it doesn't scale
    >>> (linear complexity) so for the more general case a map might be
    >>> superior.

    >>
    >> Also agree

    >
    > At a guess you'd need at least some thousand enum values in order for a
    > std::map to perform better. In that case you'd use some system instead
    > of mapping strings to individual values (and you'd not use an enum). And
    > even with the horror of thousands of non-systematic enum values a
    > std::map would be a premature optimization.
    >


    I am not talking about the performances here.

    Using the map, you can ease the implementation and maintenance effort,
    especially if you use this:
    http://www.boost.org/doc/libs/1_42_0/libs/assign/doc/index.html
    Vladimir Jovic, Apr 14, 2010
    #19
  20. thomas

    Kai-Uwe Bux Guest

    Keith H Duggar wrote:


    > unsigned types in C++ /ARE/ modular arithmetic. This is defined
    > by the standard. As to whether they "indicate", well who knows?
    > Indicate to whom? In what context?


    Agreed. Since modular reduction of values kicks in with unsigned arithmetic
    only in cases where the expression would overflow if interpreted with signed
    types, one could argue with identical strength, that signed types "indicate"
    undefined behavior. Doesn't sound right.


    > "indicate" aside, it is fact that they are modular arithmetic
    > and as such "positive" and "negative" lose distinction because
    > of modular congruence.


    Just a nit: unsigned type do not only support modular arithmetic. They still
    have operator< and the like; and all unsigned values are >= 0. In that very
    precise sense, they are all non-negative.


    Best

    Kai-Uwe Bux
    Kai-Uwe Bux, Apr 14, 2010
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Eric Sosman
    Replies:
    3
    Views:
    778
    Mayeul
    Feb 26, 2010
  2. Wojtek
    Replies:
    1
    Views:
    495
  3. Lew
    Replies:
    0
    Views:
    535
  4. Roedy Green
    Replies:
    0
    Views:
    729
    Roedy Green
    Feb 27, 2010
  5. DaveB
    Replies:
    0
    Views:
    278
    DaveB
    Apr 17, 2010
Loading...

Share This Page