Wednesday, June 17, 2015

Digest for comp.lang.c++@googlegroups.com - 25 updates in 7 topics

"K. Frank" <kfrank29.c@gmail.com>: Jun 17 06:18AM -0700

Hello Group!
 
If one were to redesign c++ without backward compatibility
as a goal, would it make sense to include both class enum
and old-fashioned (pre-c++11) enum?
 
Are there use cases where plain enum is better (enough
better to be worth the weight of having two different kinds
of enum in the language)?
 
 
Thanks.
 
 
K. Frank
"Jason C. McDonald" <indeliblebluepen@nospam.invalid>: Jun 16 03:18PM -0700

I am trying to write a function that can convert an integer to its
equivalent Ustring (or, arguably, most any string class), without having
to rely on the STL or third-party libraries. I'm also wanting to use
math as much as possible, so I don't have to use massive conditionals or
data structures.
 
This code IS working quite well, but I feel like it can be improved. Any
feedback, improvements, or whatnot?
 
---
 
Glib::ustring int_to_ustring(int num)
{
bool neg = false;
int sub = 0;
char digit;
//This is what we'll return.
Glib::ustring str = "";
 
//If number is 0, the math won't work. Just return the string "0".
if(num == 0)
{
str = "0";
return str;
}
//Else, if the number is negative...
else if(num < 0)
{
//Store that information and make the number positive.
neg = true;
num = abs(num);
}
 
//Determine place value.
int pv = 0;
do
{
//Divide by a power of ten and trunicate decimal.
sub = num / pow(10, pv);
//Increase pv.
pv++;
}
//If we got zero, then we've overshot place value.
while(sub != 0);
 
//NOTE: The above seems to sometimes make the place value two-too-large?
 
//Loop backwards through the place values.
for(pv; pv >= 0; pv--)
{
//std::cout << "10^" << pv << "::" << num;
sub = num / pow(10, pv);
num -= sub*(pow(10, pv));
//std::cout << " --> " << "[" << sub << "]" << num << std::endl;
 
if(sub < 0 || sub > 10)
{
//Throw an error. I'm just using this as a placeholder.
std::cout << "Something went really weird." << std::endl;
}
//The char code for the digit is always 48 more than the digit.
digit = sub + 48;
//If this isn't a leading zero...
if(!(str == "" && digit == '0'))
{
//This is the best way to push a char to a ustring.
str.insert(str.end(), digit);
}
}
 
//If that number was negative, insert the negative sign.
if(neg)
str.insert(str.begin(), '-');
 
return str;
}
 
 
--
The number of ways in which code can be potentially screwed up is
theoretically infinite.
www.indeliblebluepen.com
Christopher Pisz <nospam@notanaddress.com>: Jun 16 05:48PM -0500

On 6/16/2015 5:18 PM, Jason C. McDonald wrote:
> data structures.
 
> This code IS working quite well, but I feel like it can be improved. Any
> feedback, improvements, or whatnot?
 
1) what is a UString?
2) what's wrong with the STL?
2a) What's wrong with std::string?
3) Why would you want to use math for something that can be done a few
lines with the STL?
4) Massive conditionals and data structures? huh?
 
 
All of the improvements I would suggest would be to throw away the
aforementioned constraints. You really shouldn't make constraints
without very good reason. I can't say that I've heard a good reason for
using C++ without the STL to date.
 
Your statement is like, "I want to do things better, but I can't use the
better way of doing things to do it."
 
> str.insert(str.begin(), '-');
 
> return str;
> }
 
Here is my version:
 
//------------------------------------------------------------------------------
std::string IntToString(const long long & value)
{
std::ostringstream converter;
converter << value;
return converter.str();
}
 
//------------------------------------------------------------------------------
std::string UIntToString(const unsigned long long & value)
{
std::ostringstream converter;
converter << value;
return converter.str();
}
 
//--------------------------------------------------------------------------------------------------
int StringToInt(const std::string & value)
{
int result;
std::istringstream converter(value);
 
if( (converter >> result).fail() )
{
std::ostringstream msg;
msg << "Could not convert string: \"" << value << "\" to int";
throw Shared::Exception(__FILE__, __LINE__, msg.str()); // Use
your favorite exception here
}
 
return result;
}
 
//--------------------------------------------------------------------------------------------------
boost::optional<int> StringToNullableInt(const std::string & value)
{
if( value.empty() )
{
return boost::none;
}
 
return Shared::StringToInt(value);
}
 
etc. etc.
Which looks more readable and maintainable?
 
Feel free to use the C library functions instead of you are more
interested in saving the bit of performance over using streams, but are
sure to do the proper error checking.
 
Another alternative is boost::lexical_cast.
 
EDIT:
After Googling ustring, I'd opt to use std::string internally and call
the glib conversions when I needed UTF-8 only when a call was expecting
UTF-8. I am not a fan of "X uses unicode, so let's use different string
representations in our entire program." It makes messes.
 
Furthermore, it looks like yer glib::ustring has stream operators
anyway, so you can use those in the same manner.
 
 
 
--
I have chosen to troll filter/ignore all subthreads containing the
words: "Rick C. Hodgins", "Flibble", and "Islam"
So, I won't be able to see or respond to any such messages
---
"Jason C. McDonald" <indeliblebluepen@nospam.invalid>: Jun 16 04:13PM -0700

On 06/16/2015 03:48 PM, Christopher Pisz wrote:
 
>> This code IS working quite well, but I feel like it can be improved. Any
>> feedback, improvements, or whatnot?
 
> 1) what is a UString?
 
Glib::ustring is a string which has full unicode support and is a
required component of the the gtkmm library, which runs a HUGE number of
GUIs.
 
> 2) what's wrong with the STL?
Nothing inherently. It's a project-specific decision, and I'm not the
first to make it. It's a matter of efficiency w/ some hardware, i.e.
older machines. It is rather common for game engine designers to be VERY
selective about what parts of STL to use.
 
Besides, if you're using ustring, using stringstream is YET ANOTHER
import, so your program just got bigger arbitrarily.
 
> 2a) What's wrong with std::string?
Nothing inherently, except I need to use Ustring (see my reply to #1).
Also, string is inefficient in some situations. Argue w/ Jason Gregory
on that point. (author of "Game Engine Architecture".)
 
> 3) Why would you want to use math for something that can be done a few
> lines with the STL?
See above. Also, the question "why would you want to do it differently"
should set off alarm bells here. As soon as we stop trying to find more
efficient ways to do things, we start stagnating. I never rely blindly
on existing solutions. I often recreate functionality, to see if I can
improve on it. (Also, gives me a good code recipe with which to do this
in another language.) Besides that, just using someone else's solution
without understanding it is feeding into that infamous layers of
abstraction problem that Joel Spolsky pointed out.
 
> 4) Massive conditionals and data structures? huh?
The quickest hack solution to this would be using a large if statement
or an array. Unnecessary conditionals waste CPU cycles, and unnecessary
data structures waste RAM.
 
> using C++ without the STL to date.
 
> Your statement is like, "I want to do things better, but I can't use the
> better way of doing things to do it."
 
Careful of jumping to that conclusion. STL is not the for-all-end-all.
I'm not against using it, but if a simple task such as this requires me
to import an entire STL header, I'd prefer to wrap my own if I can come
close to efficiency. It yields a smaller program. I should mention that
I am targeting older systems as well as new. (Older, as in 256MB RAM or
less and 20-yr-old processors, which accounts for a surprisingly large
number of school computer labs, my target user group.)
 
--
The number of ways in which code can be potentially screwed up is
theoretically infinite.
www.indeliblebluepen.com
Christopher Pisz <nospam@notanaddress.com>: Jun 16 06:24PM -0500

On 6/16/2015 6:13 PM, Jason C. McDonald wrote:
> I am targeting older systems as well as new. (Older, as in 256MB RAM or
> less and 20-yr-old processors, which accounts for a surprisingly large
> number of school computer labs, my target user group.)
 
Fair enough. Just be careful. It's been my experience thus far that
every time I run into a code block that tries to "do what the STL does,
but better" it not only performed worse, but filled up the bug tracker
as well. Not that you are one of those people, but there exists a crowd
that takes that stance, whom never performance tested in a satisfactory
manner, and/or whom cannot compete, testing wise, with the millions of
users calling the STL vs the 5-20 calling their code.
 
I cannot comment on what to do with 20 year old computers, because I was
still learning what poke 53280,0 meant on my c64 and sneaking out of my
bedroom at night to play Elite in my batman PJs.
 
 
 
 
 
--
I have chosen to troll filter/ignore all subthreads containing the
words: "Rick C. Hodgins", "Flibble", and "Islam"
So, I won't be able to see or respond to any such messages
---
"Jason C. McDonald" <indeliblebluepen@nospam.invalid>: Jun 16 04:44PM -0700

On 06/16/2015 04:24 PM, Christopher Pisz wrote:
> that takes that stance, whom never performance tested in a satisfactory
> manner, and/or whom cannot compete, testing wise, with the millions of
> users calling the STL vs the 5-20 calling their code.
 
Absolutely. There's dangers on both sides of the line, really. Glib and
ICU are two libraries that reportedly succeed at out-performing STL,
though I haven't tested that claim personally yet. I'm using Glib
more-or-less out of necessity, since I'm relying to gtkmm for GUI
building. I tend to be wary of code libraries by default.
 
I'm actually designing a language at the moment, so that's the other
reason I'm in "recreate functionality" mode.
 
> I cannot comment on what to do with 20 year old computers, because I was
> still learning what poke 53280,0 meant on my c64 and sneaking out of my
> bedroom at night to play Elite in my batman PJs.
 
Heck, at the moment, I can't either. All I know is to be
near-pathologically stingy with memory and CPU cycles.
 
[Ahhhh, Elite. Side note, have you seen the open-source Elite-clone,
Oolite? Quite impressive.]
 
--
The number of ways in which code can be potentially screwed up is
theoretically infinite.
www.indeliblebluepen.com
"Jason C. McDonald" <indeliblebluepen@nospam.invalid>: Jun 16 05:24PM -0700

On 06/16/2015 03:18 PM, Jason C. McDonald wrote:
> data structures.
 
> This code IS working quite well, but I feel like it can be improved. Any
> feedback, improvements, or whatnot?
 
Following up on my own, thanks to a Stack Overflow discussion
(http://stackoverflow.com/a/30880365/472647). Apparently, no one online
bothered to mention the bright-blazingly-obvious solution using Glib...
 
Glib::ustring text = Glib::ustring::format(123456);
 
However, I still would like feedback on mine, as there is still those
who desire to do something like this for custom string classes without
using third-party libraries. Just ignore Glib::ustring, and insert <your
custom class> if you want to give feedback.
 
--
The number of ways in which code can be potentially screwed up is
theoretically infinite.
www.indeliblebluepen.com
Christian Gollwitzer <auriocus@gmx.de>: Jun 17 09:20AM +0200

Am 17.06.15 um 02:24 schrieb Jason C. McDonald:
> (http://stackoverflow.com/a/30880365/472647). Apparently, no one online
> bothered to mention the bright-blazingly-obvious solution using Glib...
 
> Glib::ustring text = Glib::ustring::format(123456);
 
for sure you are not the first person wanting to print data to ustring,
so I'm not very surprised you found a ready-made number formatter already.
 
> However, I still would like feedback on mine, as there is still those
> who desire to do something like this for custom string classes without
> using third-party libraries.
 
Your algorithm is a bit strange. Formatting integers is usually done by
the divide and mod algorithm, which works like this
 
if (i<0) { print "-"; i=-i }
 
i=12345678
while i {
print i % 10
i = i/10
}
 
Afterwards you reverse the digits. Calling a power library function for
each digit and doing subtracts etc. will likely be much slower than the
repeated div/mod apporach shown here. "pow" is a floating point
function. Your algorithm does repeated conversion between integer and
double, which is not going to help either accuracy or speed.
 
> Just ignore Glib::ustring, and insert <your
> custom class> if you want to give feedback.
 
I'd get a decent implementation from somewhere else instead of writing
my own. It becomes an order of magnitude more complex if you are dealing
with floating point numbers. Then you'll have to handle NaN, Inf etc. in
addition to printing the normalized value. I wouldn't recommend to roll
your own unless you implement the string library (and let me ask, why)
 
Christian
Christopher Pisz <nospam@notanaddress.com>: Jun 16 05:34PM -0500

I am getting a compiler error:
 
Error 1 error C2678: binary '[' : no operator found which takes a
left-hand operand of type 'const
std::map<int,std::vector<std::string,std::allocator<_Ty>>,std::less<_Kty>,std::allocator<std::pair<const
_Kty,std::vector<_Ty,std::allocator<_Ty>>>>>' (or there is no
acceptable conversion) c:\users\christopher.pisz\documents\visual
studio 2013\projects\test\test\main.cpp 12 1 Test
 
With the following test:
 
#include <map>
#include <vector>
 
void Foo(const std::map<int, std::vector<std::string> > & theMap)
{
// If the map does not contain a value for the key
// I'd expect it to make an empty vector and return that
// but instead, I get a compiler error
const std::vector<std::string> stuff = theMap[1];
}
 
int main()
{
std::map<int, std::vector<std::string> > myMap;
std::vector<std::string> myVector;
myVector.push_back("Hello");
myVector.push_back("Good Bye");
myMap[1] = myVector;
 
Foo(myMap);
 
return 0;
}
 
 
I thought operator[] inserted a default constructed value if one did not
exist for the given key. I'd expect "Stuff" to be an empty vector, but I
get a compiler error instead. Where did I go wrong here?
 
 
--
I have chosen to troll filter/ignore all subthreads containing the
words: "Rick C. Hodgins", "Flibble", and "Islam"
So, I won't be able to see or respond to any such messages
---
Melzzzzz <mel@zzzzz.com>: Jun 17 12:48AM +0200

On Tue, 16 Jun 2015 17:34:05 -0500
> // but instead, I get a compiler error
> const std::vector<std::string> stuff = theMap[1];
> }
 
Get rid of the "const".
Christopher Pisz <nospam@notanaddress.com>: Jun 16 05:49PM -0500

On 6/16/2015 5:48 PM, Melzzzzz wrote:
>> const std::vector<std::string> stuff = theMap[1];
>> }
 
> Get rid of the "const".
 
#include <iostream>
#include <map>
#include <vector>
 
void Foo(const std::map<int, std::vector<std::string> > & theMap)
{
// If the map does not contain a value for the key
// I'd expect it to make an empty vector and return that
// but instead, I get a compiler error
std::vector<std::string> stuff = theMap[1];
}
 
int main()
{
std::map<int, std::vector<std::string> > myMap;
std::vector<std::string> myVector;
myVector.push_back("Hello");
myVector.push_back("Good Bye");
myMap[1] = myVector;
 
Foo(myMap);
 
return 0;
}
 
Same error.
Were you referring to a different const?
 
 
--
I have chosen to troll filter/ignore all subthreads containing the
words: "Rick C. Hodgins", "Flibble", and "Islam"
So, I won't be able to see or respond to any such messages
---
Melzzzzz <mel@zzzzz.com>: Jun 17 12:50AM +0200

On Tue, 16 Jun 2015 17:49:45 -0500
> }
 
> Same error.
> Were you referring to a different const?
 
void Foo(/* this const*/ std::map<int, std::vector<std::string> > &
theMap)
Christopher Pisz <nospam@notanaddress.com>: Jun 16 06:01PM -0500

On 6/16/2015 5:50 PM, Melzzzzz wrote:
>>>> const std::vector<std::string> stuff = theMap[1];
>>>> }
 
>>> Get rid of the "const".
SNIP
 
> void Foo(/* this const*/ std::map<int, std::vector<std::string> > &
> theMap)
 
Oh I see...Is it because of the scenario where the key doesn't exist, it
would have to default construct a vector, which in turn would alter the map?
 
 
 
--
I have chosen to troll filter/ignore all subthreads containing the
words: "Rick C. Hodgins", "Flibble", and "Islam"
So, I won't be able to see or respond to any such messages
---
Melzzzzz <mel@zzzzz.com>: Jun 17 01:02AM +0200

On Tue, 16 Jun 2015 18:01:18 -0500
 
> Oh I see...Is it because of the scenario where the key doesn't exist,
> it would have to default construct a vector, which in turn would
> alter the map?
 
Exactly.
Barry Schwarz <schwarzb@dqel.com>: Jun 16 04:09PM -0700

On Tue, 16 Jun 2015 17:34:05 -0500, Christopher Pisz
>{
> // If the map does not contain a value for the key
> // I'd expect it to make an empty vector and return that
 
This part of your expectation is a run time situation, not a compile
time determination.
 
> // but instead, I get a compiler error
> const std::vector<std::string> stuff = theMap[1];
 
It compiles fine on my system if you remove the "const" from Foo's
parameter.
 
The same compiler diagnostic is issued even if you remove the "&". So
the fact that the parameter is a reference is not the problem. It
apparently has something to do with the "const". I guess the []
operator is not defined for const map.
 
It compiles fine with the const if you change theMap[1] to
theMap.at(1) in the assignment statement.
 
 
>I thought operator[] inserted a default constructed value if one did not
>exist for the given key. I'd expect "Stuff" to be an empty vector, but I
>get a compiler error instead. Where did I go wrong here?
 
You are mixing run time and compile time "performance".
 
--
Remove del for email
Christopher Pisz <nospam@notanaddress.com>: Jun 16 06:14PM -0500

On 6/16/2015 6:02 PM, Melzzzzz wrote:
 
> Exactly.
 
Excellent. Thanks for the help.
In that case, I think I want to use this alternative, so I can promise
the caller I won't alter their map. No sense in using find here, as far
as I can tell. I've never used the "at" member though.
 
void Foo(const std::map<int, std::vector<std::string> > & theMap)
{
std::vector<std::string> & stuff = std::vector<std::string>();
try
{
stuff = theMap.at(1);
}
catch(std::out_of_range &)
{
// Leave the vector empty
}
 
// Iterate over the elements and do things.
}
 
 
 
--
I have chosen to troll filter/ignore all subthreads containing the
words: "Rick C. Hodgins", "Flibble", and "Islam"
So, I won't be able to see or respond to any such messages
---
Paavo Helde <myfirstname@osa.pri.ee>: Jun 17 01:09AM -0500

Christopher Pisz <nospam@notanaddress.com> wrote in
> // I'd expect it to make an empty vector and return that
> // but instead, I get a compiler error
> const std::vector<std::string> stuff = theMap[1];
 
void Foo(const std::map<int, std::vector<std::string> > & theMap)
{
auto iter = theMap.find(1);
const std::vector<std::string> stuff =
(iter==theMap.end()? std::vector<std::string>(): iter->second);
}
 
hth
Paavo
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Jun 17 12:42AM +0100

On Tue, 16 Jun 2015 21:37:00 +0100
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
[snip]
> the conversion will work. (You do have to worry if the size of int
> is larger than the size of void*, but I know of no implementation
> where that is the case.)
 
On looking it up I think on the last point I was too pessimistic. It
seems to me that reinterpret casts of int->void*->int are obliged to
work according to the standard - in other words, sizeof(int) cannot be
larger than sizeof(void*) in a conforming implementation. In fact, it
appears that sizeof(long long) cannot be larger than sizeof(void*):
 
§5.2.10/4 of C++11: "A pointer can be explicitly converted to any
integral type large enough to hold it. The mapping function is
implementation-defined. [ Note: It is intended to be unsurprising to
those who know the addressing structure of the underlying machine. —
end note ]. ... ."
 
§5.2.10/5 of C++11: "A value of integral type or enumeration type can
be explicitly converted to a pointer. A pointer converted to an
integer of sufficient size (if any such exists on the implementation)
and back to the same pointer type will have its original value;
mappings between pointers and integers are otherwise
implementation-defined. ... ."
 
In the first sentence of §5.2.10/5 there is no qualification about sizes
for the integer->pointer conversion. The reverse conversion does have a
size qualification.
 
Chris
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Jun 17 01:12AM +0100

On Wed, 17 Jun 2015 00:42:48 +0100
> work according to the standard - in other words, sizeof(int) cannot be
> larger than sizeof(void*) in a conforming implementation. In fact, it
> appears that sizeof(long long) cannot be larger than sizeof(void*):
 
[snip]
 
Well, whatever the theory, it is not borne out by practice. On the
32-bit machines on which I have just now tested, sizeof(long long)
certainly is larger than sizeof (void*). The first is 8 and the
second is 4. But it is curious that the qualification about sizes is
omitted in the standard for integral to pointer conversions.
 
Chris
Martin Shobe <martin.shobe@yahoo.com>: Jun 16 09:01PM -0500

On 6/16/2015 2:55 PM, Victor Bazarov wrote:
 
> OK. Now consider this. It does so, and it gets called from other
> functions of the same API some time later, and the local variable has
> gone out of scope and its address contains garbage...
 
Obviously, you have to keep it around for as long as the API needs it.
 
 
>> much less? I think I detect a bit of hyperbole.
 
> Not if the lifetime has to be managed across modules or beyond one API
> call.
 
Even then. The API, in order to be usable, should have documentation
that tells you how long you have to keep it around. While I won't claim
that every case is easy, I've never encountered one where it would be hard.
 
>> }
 
> Bad idea using C-style casts, that one of the points I failed to
> deliver, I am guessing...
 
I won't disagree about the use of C-style casts, it just wasn't
important for my point so I didn't change it.
 
Martin Shobe
Victor Bazarov <v.bazarov@comcast.invalid>: Jun 16 06:07PM -0400

On 6/16/2015 5:45 PM, Doug Mika wrote:
 
> on the reference site, query vector:
> http://www.cplusplus.com/reference/vector/vector/?kw=vector
 
> when you scroll down it gives a list of Member Types. How can I know whether they are object members or class members?
 
By RTFMing, maybe?
 
V
--
I do not respond to top-posted replies, please don't ask
Victor Bazarov <v.bazarov@comcast.invalid>: Jun 16 06:14PM -0400

On 6/16/2015 5:55 PM, Paavo Helde wrote:
 
>> It's a member of the class, not a member of an object.
 
> Static member functions are also members of the class, yet can be called
> on an object. Just saying...
 
Yes, why don't we just unify anything that sounds similar? I guess it
was too much to ask of the compiler creators to allow types to be
figured out from an expression, like in a declaration:
 
(object1 @ object2).sometypename variablename;
 
(here 'object1 @ object2' is an expression that yields another object,
of some type. The Standard writers agreed that to simplify the parsing
(again, I'm guessing here) you need to write
 
decltype(...) :: sometypename ...
 
since 'decltype' yields a *type*, and not an instance, you need to use
the scope resolution operator to get to a member type.
 
V
--
I do not respond to top-posted replies, please don't ask
Victor Bazarov <v.bazarov@comcast.invalid>: Jun 16 05:06PM -0400

On 6/16/2015 5:02 PM, Richard wrote:
 
>> IOW, 'new foo' ignores the individuals member initializers while 'new
>> foo{}' uses those.
 
> I don't think this is quite right about 'new foo' as per above.
 
You're likely right, and I wasn't reading the Standard carefully. I am
guessing it mostly differs for the members that *don't have* an
initializer specified for them.
 
V
--
I do not respond to top-posted replies, please don't ask
legalize+jeeves@mail.xmission.com (Richard): Jun 16 09:13PM

[Please do not mail me a copy of your followup]
 
Noob <root@127.0.0.1> spake the secret code
 
>On 16/06/2015 22:16, Noob wrote:
 
>> What version of Visual C++ fully supports C++11?
 
>Looking bleak.
 
Not really. Most programmers are not going to need every single C++11
feature in the core language, never mind all the features in the
library.
 
>to be completely fixed in 2015 RTM.
 
...which is about to drop any day now.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
ram@zedat.fu-berlin.de (Stefan Ram): Jun 16 02:57PM

>but this gives error when p is 64 bit and int 32 bit.
>I can cast to long but long does not have to be 64 bit,either.
>What do you suggest?
 
uintptr_t
18.4.1 Header <cstdint> synopsis [cstdint.syn]
 
But seriously, to take a step backwards and ask
why this is necessary.
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: