Wednesday, June 17, 2015

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

"K. Frank" <kfrank29.c@gmail.com>: Jun 17 02:19PM -0700

Hello Paul!
 
On Tuesday, June 16, 2015 at 3:12:30 PM UTC-4, Paul wrote:
> I tried the problem of generating solutions like 123 - 45 - 67 + 89 = 100. The point is that we get 100 and we use the digits from 1 to 9 in consecutive order.
> My code is really ugly, and it also took me ages to do. Any insights on how I can improve it? The problem is stated more accurately in the initial comments.
> Many thanks for your help.
 
I have some thoughts, but take them with a grain of
salt. There are generally lots of different ways of
doing things.
 
There are also style preferences for how much generality,
abstraction, and hewing to prescriptive "good practices"
one wants to deal with.
 
> Write a program that outputs all possibilities to put + or - or nothing between the numbers 1, 2, ..., 9 (in this order)
> such that the result is always 100. For example: 1 + 2 + 34 - 5 + 67 - 8 + 9 = 100.*/
 
> // First a utility function that inserts + and - into a vector of numbers to get a result
 
There is a question of what level of granularity one wants
for helper functions for a problem like this. You only call
insertSigns once in your code. If it were me, I might not
package a code fragment like this in a separate function.
(But that's just me.)
 
> int insertSigns (const std::vector<int>& numbers, const std::string& plusesAndMinuses)
> ...
 
I think you can simplify things (get rid of things like
concatenate and insertSigns and so on) if you organize
your problem as follows:
 
Recognize that there are three ways of linking neighboring
digits together: a plus sign, a minus sign, or concatenate
the digits together to form a multi-digit number.
 
Thus, maybe
 
enum Operation { concat, plus, minus };
 
> ...
 
> // Generate all combinations of plus/minus signs of a given length. Use recursion
 
First, you have stated a specific problem (single digits,
1 through 9, in order), and you haven't stated a generalized
version of the problem. I would therefore write specific
code -- I would bake the specifics of the problem into my
data and algorithm -- rather than write more general helper
functions. If you write a more general function, you (or
at least I) can't say whether it's right or wrong, because
you haven't set forth the more general specification that
your function should satisfy.
 
So I might use the following data structure:
 
const int nOperations = 8;
// there are eight concat's, '+'s, or '-'s inserted
// between 9 digits.
Operation operations[nOperations];
 
I would lean against recursion, and just use a simple
loop. There are 3^8 = 6561 choices for how you insert
concat, '+', or '-' between the 9 digits. (That is, the
data structure operations can take on 3^8 distinct values.)
 
> // Generate all vectors of numbers that can arise from concatenations in a list of numbers
> // Numbers can only be concatenated with their neighbours. Use recursion
> std::vector<std::vector<int>> concatenation (const std::vector<int>& numbers, int base = 10)
 
(Again, without a more general problem having been stated,
I would elect not to support the generality of having a
base other than 10.)
 
Again, I would use a loop rather than recursion. Also, if
you use an array (or vector, etc) of Operations as your
primary data structure, the loop where you generate the
pluses and minuses and the (implicit) loop where you (implicitly)
generate your concatenations can be one and the same.
 
> ...
 
Anyway, just some thoughts.
 
 
Good luck.
 
 
K. Frank
Luca Risolia <luca.risolia@linux-projects.org>: Jun 17 05:32PM +0200

On 17/06/2015 15:18, K. Frank wrote:
> 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?
 
Why not (see below).
 
> 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)?
 
old-style enum's can make the code more readable in some cases. For
example, I find them useful for getting elements from tuples or pairs:
 
enum {Description, RGB};
 
std::map<std::string, std::uint32_t> colors = {
{"white", 0xffffff}, {"black", 0x000000} /*...*/
};
 
// somewhere else...
for (const auto& c : colors)
std::cout << std::get<Description>(c) << ' '
<< std::hex << std::get<RGB>(c) << '\n';
 
The same readability cannot be achieved with strongly typed enums (or
type aliases).
 
There are other cases in template metaprogramming where they are useful.
"K. Frank" <kfrank29.c@gmail.com>: Jun 17 12:24PM -0700

Hi Luca!
 
On Wednesday, June 17, 2015 at 11:33:01 AM UTC-4, Luca Risolia wrote:
> << std::hex << std::get<RGB>(c) << '\n';
 
> The same readability cannot be achieved with strongly typed enums (or
> type aliases).
 
Nice example.
 
> There are other cases in template metaprogramming where they are useful.
 
Are all of the use cases you have in mind based
on the fact that you can templatize on integral
values, but not other kinds of values, and therefore
there is a role for (old-fashioned) enums that are
integral types?
 
If you were redesigning c++ (without regard to
backward compatibility), given that each additional
language feature adds complexity, would you
 
keep both kinds of enums (with this
template usage in mind);
 
keep only class enums, and work out
some other way to templatize on class
enums;
 
or keep only class enums and forgo the
ability to templatize on enums?
 
 
Thanks.
 
 
K. Frank
Thomas 'PointedEars' Lahn <PointedEars@web.de>: Jun 17 03:03PM

Victor Bazarov wrote:
 
>> I used the hammer »placement new«.
 
> Yes, you did. Your program still has undefined behavior. See my other
> reply to your use of placement new.
 
Where is it?
 
Victor Bazarov <v.bazarov@comcast.invalid>: Jun 17 12:05PM -0400

On 6/17/2015 11:03 AM, Thomas 'PointedEars' Lahn wrote:
 
>> Yes, you did. Your program still has undefined behavior. See my other
>> reply to your use of placement new.
 
> Where is it?
 
I'm not sure how to lead you to it precisely... It's in this thread, in
answer to Stefan's "Now, why /does/ the following work?" which he posted
(as reported by my Thunderbird) on 6/15/2015 at 10:18 PM; my reply dated
10:42 PM same day.
 
> [..]
 
V
--
I do not respond to top-posted replies, please don't ask
Bo Persson <bop@gmb.dk>: Jun 17 05:19PM +0200

On 2015-06-16 19:47, Richard wrote:
 
>> intptr_t and/or uintptr_t from cstdint. Although they don't
>> have to exist.
 
> It's kinda annoying that these are optional.
 
Yes, but it allows C and C++ to be implemented on systems where void* is
larger than all integer types.
 
For example word-addresses machines where char* and void* can be larger
than int*.
 
 
 
Bo Persson
Bo Persson <bop@gmb.dk>: Jun 17 05:24PM +0200

On 2015-06-16 20:16, Melzzzzz wrote:
 
> Too ,bad ;(
> I need intptr_t as conversion is actually passing int parameter as void*
> and than back to int.
 
If you limit yourself to systems where the types exist, that might be
all you need. Systems where these types are missing are extremely rare,
and you might not want to run your programs there anyway, because of
other peculiarities of these systems (like 48-bit ints, etc).
 
 
Bo Persson
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: