How to elegantly get the enum code from its string type

T

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,
};
------------------------------------------------------------------------

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
 
A

Alf P. Steinbach

* 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
 
A

Alf P. Steinbach

* Leigh Johnston:
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
 
A

Alf P. Steinbach

* Leigh Johnston:
Alf P. Steinbach said:
* Leigh Johnston:
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
 
A

Alf P. Steinbach

* Leigh Johnston:
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
 
K

Keith H Duggar

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
 
K

Keith H Duggar

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
 
A

Alf P. Steinbach

* 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
 
A

Alf P. Steinbach

* Leigh Johnston:
Alf P. Steinbach said:
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
 
W

werasm

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;
};
 
T

tonydee

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';
}
 
V

Vladimir Jovic

Leigh said:
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?
 
A

Alf P. Steinbach

* Vladimir Jovic:
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
 
A

Alf P. Steinbach

* Leigh Johnston:
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
 
K

Kai-Uwe Bux

Leigh said:
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
 
A

Alf P. Steinbach

* Leigh Johnston:
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
 
K

Keith H Duggar

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
 
A

Alf P. Steinbach

* Leigh Johnston:
I didn't claim otherwise

, 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.

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.

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
 
V

Vladimir Jovic

Alf said:
* Vladimir Jovic:

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.
'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
 
K

Kai-Uwe Bux

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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top