Monday, June 15, 2015

Digest for comp.lang.c++@googlegroups.com - 22 updates in 8 topics

ram@zedat.fu-berlin.de (Stefan Ram): Jun 15 07:33PM

Google Groups poster writes:
>/* Problem 2
>Write a function that combines two lists by alternatingly taking elements. For example:
>given the two lists [a, b, c] and [1, 2, 3], the function should return [a, 1, b, 2, c, 3].
 
In C++, the notation »[ a, b, c ]« seems to be an array
index with a comma operator. For example, the following
program prints »d«.
 
#include <iostream>
#include <ostream>
#include <string>
 
using namespace ::std::literals;
 
int main()
{ int const a = 1;
int const b = 2;
int const c = 3;
::std::cout << "abcdef"[ a, b, c ]<< "\n"s; }
 
So, »[ a, b, c ]« is not a list in C++ as far as I can see.
 
Maybe the author of the Problem has invented his own
notation, but then we would need to see its definition.
 
To give a list in C++, one can use
 
#include <string>
#include <initializer_list>
#include <list>
using namespace ::std::literals;
 
::std::list< ::std::string >{ "a"s, "b"s, "c"s }
 
(this is not a program, just the list expression preceded by
the necessary includes).
 
>A difficult technicality is that it seems that the elements
>can come from different types -- ints and chars.
 
»1« in C++ is an int. But »a« is not a char, its a name.
To be able to correctly interpret the custom notation of
the author of the Problem, we need to see its specification.
ram@zedat.fu-berlin.de (Stefan Ram): Jun 15 08:55PM

>»1« in C++ is an int. But »a« is not a char, its a name.
>To be able to correctly interpret the custom notation of
>the author of the Problem, we need to see its specification.
 
I am just a beginner when it comes to class definitions in
C++, especially with virtual functions!
 
I wrote two classes »IntListEntry« and »CharListEntry«.
Each has a virtual function »print«. So I was hoping that
»entry.print( stream )« would call one of these two virtual
functions. But instead it calls the base-class »print«!
 
Why?
 
The following program prints this:
 
I now add an IntListEntry to the list.
I now add a CharListEntry to the list.
I now want to do a virtual call.
The base-class print is called.
 
I now want to do a virtual call.
The base-class print is called.
 
What is the smallest change to the program that will
make »entry.print( stream )« call the appropriate
print method from either »IntListEntry« or »CharListEntry«.
 
(BTW: I have not defined a virtual destructor because
I believe that there are no allocations with dynamic
life-time here.)
 
Another issue is memory: I was hoping that all the objects
of ListEntry, IntListEntry and CharListEntry have the same
size, so that I can put them directly into the
::std::list< ListEntry > without a pointer indirection.
But I am not sure about this either. (sizeof shows them
to be the same here, but I don't know whether this is
guaranteed.)
 
#include <iostream>
#include <ostream>
#include <string>
#include <initializer_list>
#include <list>
 
using namespace ::std::literals;
 
struct ListEntry
{ int i;
ListEntry( int const i ): i( i ){}
virtual ::std::ostream & print( ::std::ostream & stream )
{ ::std::cout << "The base-class print is called.\n";
return stream; }; };
 
struct IntListEntry : public ListEntry
{ IntListEntry( int const i ): ListEntry( i ){}
virtual ::std::ostream & print( ::std::ostream & stream )const
{ return stream << ::std::to_string( i ); }};
 
struct CharListEntry : public ListEntry
{ CharListEntry( char const c ): ListEntry( static_cast< int >( c )){}
virtual ::std::ostream & print( ::std::ostream & stream )const
{ return stream << ::std::to_string( static_cast< char >( i )); }};
 
static inline void push_back
( ::std::list< ListEntry >& list, int const i )
{ ::std::cout << "I now add an IntListEntry to the list.\n";
list.push_back( IntListEntry( i )); }
 
static inline void push_back
( ::std::list< ListEntry >& list, char const c )
{ ::std::cout << "I now add a CharListEntry to the list.\n";
list.push_back( CharListEntry( c )); }
 
static inline ::std::ostream& operator <<
( ::std::ostream & stream, ListEntry & entry )
{ ::std::cout << "I now want to do a virtual call.\n";
return entry.print( stream ); }
 
int main()
{ ::std::list< ListEntry >list;
push_back( list, 1 );
push_back( list, 'a' );
::std::cout << list.front() << "\n"s;
::std::cout << list.back() << "\n"s; }
ram@zedat.fu-berlin.de (Stefan Ram): Jun 15 11:16PM

>You can't have a list of base class objects and hope to squeeze derived
>objects into it (there is not enough room!). What you get instead is a
>behavior called slicing, look it up.
 
But - as I wrote before - here I executeed:
 
::std::cout << sizeof( ListEntry )<< '\n';
::std::cout << sizeof( IntListEntry )<< '\n';
::std::cout << sizeof( CharListEntry )<< '\n';
 
and always got the same value »16«.
 
>There is a school of thought that base class virtual functions should all
>be declared pure and only leaf classes should implement them.
 
I did so, but then implemented the virtual function in the base
for debugging purposes.
 
>Following this style would have given an early compile error
>with your code as there would have been no way to create base
>class objects, let alone putting them into a container.
 
IIRC, I never create base class objects, only derived objects:
 
static inline void push_back
( ::std::list< IntermediateEntry >& list, int const i )
{ list.push_back( IntListEntry( i )); }
 
static inline void push_back
( ::std::list< IntermediateEntry >& list, char const c )
{ list.push_back( CharListEntry( c )); }
 
...
 
push_back( list, 1 );
push_back( list, 'a' );
 
I thought that the two different objects of the two different
derived classes would carry two different vtbls with them,
so each would carry with it its own virtual methods.
 
It is really difficult to put a CharListEntry into the List!
I now even tried a more aggressive function:
 
static inline void push_back
( ::std::list< IntermediateEntry >& list, char const c )
{ ::std::cout << "I now add a CharListEntry to the list.\n";
::std::list< CharListEntry >*l = reinterpret_cast<::std::list< CharListEntry >*>(&list);
l->emplace_back( c ); }
 
but to no avail! it compiled, but still does not behave as
intended.
 
Even when I really get super-aggressive, the following
program still prints »B«:
 
#include <iostream>
#include <ostream>
#include <cstring>
 
struct B { virtual void p() { ::std::cout << "B\n"; }};
struct D : public B { void p() { ::std::cout << "D\n"; }};
int main()
{ B b; D d; memcpy(( void * )&b, ( void * )&d, sizeof b ); b.p(); }
 
it prints »B« as if d would /not/ have its own vtbl pointer
that is being copied with memcpy.
 
FYI: This
 
#include <iostream>
#include <ostream>
 
struct B { virtual void p() { ::std::cout << "B\n"; }};
struct D : public B { void p() { ::std::cout << "D\n"; }};
int main()
{ B b; D d;
::std::cout << sizeof b << '\n';
::std::cout << sizeof d << '\n'; }
 
prints
 
8
8
 
here. So the sizes /are/ the same.
skynet3269@gmail.com: Jun 15 03:55PM -0700

1-800 AUTO YES is the top performing, highest paying auto-loan lead generating program. Our performance pricing gives publishers the opportunity to earn enormous cash - as much as $12.00 per lead just by providing users with a FREE online auto loan application form. It takes seconds to apply resulting in incredible conversions for you .
http://www.1800freshstart.com/?src=42051&lnk=74248
Paul <pepstein5@gmail.com>: Jun 15 01:19PM -0700

On Monday, June 15, 2015 at 7:33:43 PM UTC+1, Paavo Helde wrote:
> loosely typed language than C++?
 
> hth
> Paavo
 
This is my latest attempt along those lines but it doesn't even compile. The error message is invalid use of union, presumably because first.twoTypes.type1 = firstType[i]; is the wrong syntax.
Thank you for any help you can offer.
 
Paul
 
 
/* Problem 2
Write a function that combines two lists by alternatingly taking elements. For example: given the two lists [a, b, c] and [1, 2, 3], the function should return [a, 1, b, 2, c, 3].
A difficult technicality is that it seems that the elements can come from different types -- ints and chars.
Problem doesn't say how to handle the case where lists have different lengths. Will simply add on the remaining elements.
*/
template<typename elementType1, typename elementType2>
 
struct TwoTypes{
 
bool firstType; // True if we intend the union member to be of the first type false otherwise.
 
public:
union twoTypes
{
elementType1 type1;
elementType2 type2;
};
 
TwoTypes(bool first) : firstType(first)
{
 
}
};
 
template <typename elementType1, typename elementType2>
std::ostream& operator << (std::ostream& out, const TwoTypes<elementType1, elementType2>& types)
{
return types.firstType ? out << types.twoTypes.type1 : out << types.twoTypes.type2;
}
 
template <typename elementType1, typename elementType2>
std::vector <TwoTypes <elementType1, elementType2> > amalgamate(const std::vector<elementType1>& firstType, const std::vector<elementType2>& secondType)
{
std::vector <TwoTypes <elementType1, elementType2> > results;
int min = std::min(firstType.size(), secondType.size());
int max = std::max(firstType.size(), secondType.size());
 
for(int i = 0; i < min; ++i)
{
TwoTypes<elementType1, elementType2> first = true;
TwoTypes <elementType1, elementType2> second = false;
first.twoTypes.type1 = firstType[i];
second.twoTypes.type2 = secondType[i];
 
results.push_back(first);
results.push_back(second);
}
 
for(int i = min; i < max; ++i)
{
bool first = firstType.size() > secondType.size();
TwoTypes<elementType1, elementType2> additional(first);
 
if(first)
additional.twoTypes.type1 = firstType[i];
else
additional.twoTypes.type2 = secondType[i];
 
results.push_back(additional);
}
 
return results;
}
 
void testProblem2()
{
const std::vector<char> firstVec = {'a', 'b', 'c'};
const std::vector<int> secondVec = {1, 2, 3};
const std::vector<int> differentSizeVec = {1,2,3,4,5};
std::vector<TwoTypes<char, int> > results = amalgamate(firstVec, secondVec);
std::cout << " A vector of " << firstVec.size() << " chars interspersed with a vector of " << secondVec.size() << " numbers gives a result as follows ";
 
for (auto i : results)
std::cout << std::endl << i;
 
results = amalgamate(firstVec, differentSizeVec);
std::cout << std::endl << " A vector of " << firstVec.size() << " chars interspersed with a vector of " << differentSizeVec.size() << " numbers gives a result as follows ";
 
for (auto i : results)
std::cout << std::endl << i;
}
Paavo Helde <myfirstname@osa.pri.ee>: Jun 15 03:45PM -0500

Paul <pepstein5@gmail.com> wrote in
 
> This is my latest attempt along those lines but it doesn't even
> compile. The error message is invalid use of union, presumably because
> first.twoTypes.type1 = firstType[i]; is the wrong syntax. Thank you
 
Here you are using 'twoTypes' as member name...
 
> elementType1 type1;
> elementType2 type2;
> };
 
... but here you define it as a type name. Plus, your class does not
contain any member of this type. Change the union piece to:
 
union
{
elementType1 type1;
elementType2 type2;
} twoTypes;
 
and it should at least compile.
 
hth
Paavo
Paul <pepstein5@gmail.com>: Jun 15 01:51PM -0700

On Monday, June 15, 2015 at 9:45:31 PM UTC+1, Paavo Helde wrote:
 
> and it should at least compile.
 
> hth
> Paavo
 
Not only does it compile but the results are as intended. Many thanks.
 
Paul
Paavo Helde <myfirstname@osa.pri.ee>: Jun 15 05:28PM -0500

ram@zedat.fu-berlin.de (Stefan Ram) wrote in news:virtual-20150615224232
> functions. But instead it calls the base-class »print«!
 
 
> int main()
> { ::std::list< ListEntry >list;
 
You can't have a list of base class objects and hope to squeeze derived
objects into it (there is not enough room!). What you get instead is a
behavior called slicing, look it up.
 
Using polymorphic classes is usually done via pointers (raw or smart) and
dynamically allocated objects, e.g.
 
std::list<std::unique_ptr<ListEntry>>.
 
There is a school of thought that base class virtual functions should all
be declared pure and only leaf classes should implement them. Following
this style would have given an early compile error with your code as
there would have been no way to create base class objects, let alone
putting them into a container.
 
hth
Paavo
Doug Mika <dougmmika@gmail.com>: Jun 15 02:10PM -0700

On Monday, June 15, 2015 at 1:52:26 PM UTC-5, Richard wrote:
> The Computer Graphics Museum <http://computergraphicsmuseum.org>
> The Terminals Wiki <http://terminals.classiccmp.org>
> Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
 
Yes, the problem is with constexpr, in particular, I'm having problems understanding when can I declare a function as constexpr?
 
So here I came upon a constexpr factorial function:
constexpr int fac(int n) { return (n<2)?1:n*fac(n-1); }
 
But if constexpr functions must be evaluated at compile-time, then how will the compiler know the size of n at compile time, especially if n is a user-input variable?
legalize+jeeves@mail.xmission.com (Richard): Jun 15 09:30PM

[Please do not mail me a copy of your followup]
 
Doug Mika <dougmmika@gmail.com> spake the secret code
 
>Yes, the problem is with constexpr, in particular, I'm having problems
>understanding when can I declare a function as constexpr?
 
See <http://en.cppreference.com/w/cpp/language/constexpr> for a list of
requirements on constexpr functions.
 
 
>But if constexpr functions must be evaluated at compile-time, then how
>will the compiler know the size of n at compile time, especially if n is
>a user-input variable?
 
You can't invoke this function at compile-time without specifying the
value for n as some integral type constant or constant expression.
--
"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>
scott@slp53.sl.home (Scott Lurndal): Jun 15 07:43PM


>>Int has always been signed and had four sizes for me over the years: 36
>>bits,
 
>DECsystem-10/20?
 
Or Burroughs Large Systems. Or Univac 1100/2200.
Lynn McGuire <lmc@winsim.com>: Jun 15 02:52PM -0500

On 6/15/2015 1:51 PM, Richard wrote:
 
>> The UNIVAC 1108 was a 36 bit word, 6 byte word machine.
 
> Ah.
 
> Did I guess the 60-bit machine right?
 
Yes. Model 7600. Another 6 bit machine with TEN bytes per word.
 
Lynn
Francis Glassborow <francis.glassborow@btinternet.com>: Jun 15 02:54PM -0600

On 15/06/2015 20:02, Mr Flibble wrote:
> *dangerous behaviour*. If you want a type that behaves like 'int' then
> you should be explicit about it in your code by using 'int_fast16_t' but
> absolute care must be taken when using such variable types.
 
If my code becomes dangerous I am already in undefined behaviour land
and that effectively means that I am relying on some behaviour that
breaks if int has more than 16-bits. Please give an example of code
which works for a 16-bit int but is broken for an int with more bits.
 
 
 
> You should be writing code such that the underlying type doesn't
> actually matter; that is part of the rationale for <cstdint> in the
> first place.
 
Not really, the idea was to allow systems that had more types available
over and above those required by the standard to allow programmers to
express their needs. And the rationale was a purely C one and I doubt
that it would be in C++ other than for compatibility reasons.
 
For example it is possible that on a particular platform a 32-bit
integer type performs faster than a 16-bit one. However that has a smell
of premature optimisation.
 
In reality very few if any programmers have ever made use of those
extended types, and where they have, they are often not portable (there
is no guarantee that any of the exact types exist on a platform)
 
Anyway you are free to use anything you want even if most of us would
not do so and would often ask for change in a code review. Typedefs are
a potential source of problems, particularly in C++ where overloading
can be changed by a change in an underlying type.
 
 
 
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
scott@slp53.sl.home (Scott Lurndal): Jun 15 08:56PM

>>>bits,
 
>>DECsystem-10/20?
 
>Or Burroughs Large Systems. Or Univac 1100/2200.
 
Currently known as Unisys Clearpath Libra (Burroughs) and
Clearpath Dorado (Univac).
scott@slp53.sl.home (Scott Lurndal): Jun 15 08:58PM


>> Ah.
 
>> Did I guess the 60-bit machine right?
 
>Yes. Model 7600. Another 6 bit machine with TEN bytes per word.
 
Burroughs medium systems. from 1/2 to 50 bytes per word.
 
(Variable length BCD operations up to 100 units in length, units
in either nibbles or bytes (where the zone digit is ignored)).
 
Not a natural system for C or C++.
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Jun 15 03:54PM -0600

On 15/06/2015 21:54, Francis Glassborow wrote:
 
> In reality very few if any programmers have ever made use of those
> extended types, and where they have, they are often not portable (there
> is no guarantee that any of the exact types exist on a platform)
 
Can you back that assertion up with any facts at all?
 
> not do so and would often ask for change in a code review. Typedefs are
> a potential source of problems, particularly in C++ where overloading
> can be changed by a change in an underlying type.
 
You are speaking for a lot of people there. As far as code reviews are
concerned the MISRA C++ coding standard for safey critical systems
prohibits the use of basic numerical types and mandates the use of the
typedefs from <cstdint> (or an equivalent).
 
You should be coding to an interface; if the interface is legacy and
takes an 'int' then you should of course perform a safe type conversion
to an 'int' however any new interfaces that are within your remit to
define should be using the typedefs from <cstdint> to ensure
cross-platform portability and correct program operation.
 
/Flibble
 
 
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
James Kuyper <jameskuyper@verizon.net>: Jun 15 03:55PM -0600

On 06/15/2015 03:02 PM, Mr Flibble wrote:
 
> On 15/06/2015 18:22, Francis Glassborow wrote:
...
> is the *at least* part: it can mean *different* sizes and value ranges
> on *different* implementations resulting in *different* or even
> *dangerous behaviour*. If you want a type that behaves like 'int' then
 
And how is that different from int_fast16_t?
 
> you should be explicit about it in your code by using 'int_fast16_t' but
> absolute care must be taken when using such variable types.
 
Please show code which uses 'int' when you think it should be using
'int_fast16_t', and explain the circumstances under which such code is
dangerous.
 
...
 
> You should be writing code such that the underlying type doesn't
> actually matter; that is part of the rationale for <cstdint> in the
> first place.
 
It is quite feasible to write code using short int, int, and long int,
where the underlying type doesn't actually matter. I have no objections
to <cstdint>, and would in fact have preferred it if C/C++ had adopted
types with such definitions from the very beginning, rather than adding
them on later. However, you exaggerate the problem when you claim that
that the older type names should never be used.
--
James Kuyper
 
 
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Robert Wessel <robertwessel2@yahoo.com>: Jun 15 04:02PM -0500

On Mon, 15 Jun 2015 14:52:41 -0500, Lynn McGuire <lmc@winsim.com>
wrote:
 
 
>> Ah.
 
>> Did I guess the 60-bit machine right?
 
>Yes. Model 7600. Another 6 bit machine with TEN bytes per word.
 
 
Unless you were using it to store six 10-bit characters per word.
Vir Campestris <vir.campestris@invalid.invalid>: Jun 15 09:43PM +0100

On 15/06/2015 07:08, Noob wrote:
> What is the equivalent syntax for 0 initializing an int array?
 
> int array[20] = { 0 };
 
> like in C?
 
I've just been cursing GCC over this. We have warnings-as-errors and
warnings turned up full. It then complains that I haven't initialised
all the elements. (in my case it's a struct, not an int)
 
Andy.
Victor Bazarov <v.bazarov@comcast.invalid>: Jun 15 04:51PM -0400

On 6/15/2015 4:43 PM, Vir Campestris wrote:
 
> I've just been cursing GCC over this. We have warnings-as-errors and
> warnings turned up full. It then complains that I haven't initialised
> all the elements. (in my case it's a struct, not an int)
 
Drop the 0 from between the curly braces. Is it happier now?
 
V
--
I do not respond to top-posted replies, please don't ask
"A. Bolmarcich" <aggedor@earl-grey.cloud9.net>: Jun 15 02:15PM -0500

On 2015-06-12, Doug Mika <dougmmika@gmail.com> wrote:
[snip]
> 1)How would this sort template look if we were to not have using Iter = Iterator_type<C>;? What does this line do? - I have never seen it used in this context.
> 2)What is Iterator_type and Iterator_category? I searched for these on www.cplusplus.com but found nothing that would make it clear.
 
> Thanks to all for reading something this long.
 
Other replies have answered those question. I think it is useful to add that
after the program defined aliases Iter, Iterator_type, and Iterator_category
are applied the third argument of the call to sort_helper is (including
namespace qualification)
 
typename std::iterator_traits(typename C::iterator)::iterator_category {}
 
It creates an object whose type corresponds to the iterator_category of
the iterator_traits of an iterator of a container of type C. The type of
that object is used to select which of the overloaded sort_helper function
templates to instantiate (at compile time) and call (at run time).
 
When C is a vector, the third argument is of type
std::random_access_iterator_tag. When C is a list, the third argument is of
type std::forward_iterator_tag.
Paul <pepstein5@gmail.com>: Jun 15 08:46AM -0700

On Monday, June 15, 2015 at 2:34:17 PM UTC+1, Victor Bazarov wrote:
 
> There are two versions of 'vector::begin' member function. Perhaps
> codeblocks doesn't know which one to show and picks the apparently wrong
> one...
 
Yes, if vect is a const vector, then vect.begin() is a const_iterator.
 
Thanks,
 
Paul
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: