Monday, April 20, 2015

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

ram@zedat.fu-berlin.de (Stefan Ram): Apr 19 11:30PM

Can one define a function only in the case that a function
is not declared?
 
For example, define »make_unique« at the top of a
translation unit with lines that only have this effect
when make_unique is not already declared at this point?
ram@zedat.fu-berlin.de (Stefan Ram): Apr 20 12:45AM

>On 4/19/2015 7:30 PM, Stefan Ram wrote:
>>Can one define a function only in the case that a function
>>is not declared?
...
>What problem are you trying to solve?
 
I want to write my code (e.g. for my tutorial) already in
the C++14 style, e.g., using »::std::make_unique« instead
of »::std::unique( new ...«.
 
Some implementations do not already supply »make_unique«,
so I thought about adding some lines at the top that define
»make_unique« if it's not declared at this point.
ram@zedat.fu-berlin.de (Stefan Ram): Apr 20 04:44PM

>Subject: Quick Question
 
You should use more specific subject lines in Usenet.
ram@zedat.fu-berlin.de (Stefan Ram): Apr 20 04:49PM

>The official definition of cin.get(cStr, n) is as follows:
>std::istream::get
>istream& get (char* s, streamsize n);
 
That's a declaration, not a definition.
 
>char someString[256];
>cin.get(someString, 255);
>we ignore the return type istream&?
 
You use the expression statement in the second line of the
typed code given. This is the most fundamental statement in
C++ taught at the beginning of beginner courses.
 
The return type of »get« is not even consciously ignored in
this case, it just doesn't matter.
 
>What purpose does this return type serve?
 
I assume that the return value is the target object.
In this case, it would allow one to write
 
cin.get( s, 255 ).get( s1, 255 );
 
.
ram@zedat.fu-berlin.de (Stefan Ram): Apr 20 04:55PM

>(according to www.cplusplus.com & www.cppreference.com):
>void open (const char* filename, ios_base::openmode mode = ios_base::in);
>void open (const string& filename, ios_base::openmode mode = ios_base::in);
 
This is called a »declaration« or part of what is called a
»synopsis«.
 
>Why isn't the open member function that takes one parameter
>part of the www.cplusplus.com std::ifstream::open definition?
 
It /is/ there. Because the second parameter is declared with
a default value, it can be omitted.
 
It might help you to read a good textbook, such as »The C++
programming language, fourth edition« by Bjarne Stroustrup.
ram@zedat.fu-berlin.de (Stefan Ram): Apr 20 10:24PM

>Which methods (copy constructor, copy assignment operator,....)
>must Carp and Tuna implement for the std::copy function to work
>properly (to perform a deep copy on my vector)?
 
If you want to use the "algorithm" "::std::copy", then it
seems that you need to use a custom "smart pointer" class
for your objects that deep-copies it pointees when copied.
 
The following code shows a deep copy of a vector of pointers
/without/ ::std::copy (not fully tested).
 
#include <iostream>
#include <ostream>
#include <memory>
#include <vector>
 
struct Fish
{ virtual void print() = 0;
virtual ::std::unique_ptr< Fish >clone() = 0; };
 
class Tuna : public Fish
{ void print () override { puts( "Tuna" ); }
::std::unique_ptr< Fish >clone () override
{ return ::std::make_unique< Tuna >( *this ); }};
 
class Carp : public Fish
{ void print () override { puts( "Carp" ); }
::std::unique_ptr< Fish >clone () override
{ return ::std::make_unique< Carp >( *this ); }};
 
int main()
{ ::std::vector< ::std::unique_ptr< Fish >> v;
v.push_back( ::std::make_unique< Tuna >() );
v.push_back( ::std::make_unique< Carp >() );
::std::vector< ::std::unique_ptr< Fish >> w;
for( auto & f: v )w.push_back( f->clone() ); /* copying is here */
for( auto & f: w )f->print(); }
Doug Mika <dougmmika@gmail.com>: Apr 20 01:58PM -0700

Hi
 
I have a base class called Fish, from this base class I derive two classes called Tuna and Carp
 
I create a vector<Fish> into which I place new objects of Tuna and Carp.
ie
vector<Fish> vecOfFish;
vecOfFish.push_back(new Tuna());
vecOfFish.push_back(new Carp());
...
 
Now I want to create a second vector of Fish
vector<Fish> vecOfFish2;
 
and copy the first vector into the second using std::copy.
 
Which methods (copy constructor, copy assignment operator,....) must Carp and Tuna implement for the std::copy function to work properly (to perform a deep copy on my vector)?
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Apr 20 10:23PM +0100

On 20/04/2015 21:58, Doug Mika wrote:
 
> I create a vector<Fish> into which I place new objects of Tuna and Carp.
> ie
> vector<Fish> vecOfFish;
 
I think you meant vector<Fish*> but use vector<std::unique_ptr<Fish>>
instead so you don't have to worry about memory leaks.
 
> vector<Fish> vecOfFish2;
 
> and copy the first vector into the second using std::copy.
 
> Which methods (copy constructor, copy assignment operator,....) must Carp and Tuna implement for the std::copy function to work properly (to perform a deep copy on my vector)?
 
A naked pointer doesn't have any methods so it is not possible using
std::copy on the vector to do a "deep" copy; perhaps use std::transform
instead sausages.
 
/Flibble
Paavo Helde <myfirstname@osa.pri.ee>: Apr 20 04:28PM -0500

Doug Mika <dougmmika@gmail.com> wrote in
> vector<Fish> vecOfFish;
> vecOfFish.push_back(new Tuna());
> vecOfFish.push_back(new Carp());
 
This does not compile. You have defined a vector of Fish objects, but are
pushing in pointers to objects instead of objects.
 
For getting polymorphic behavior you need a vector of some kind of
pointers. Instead of plain pointers better consider some kind of smart
pointers, e.g.
 
vector<std::shared_ptr<Fish>> vecOfFish;
vecOfFish.push_back(std::shared_ptr<Fish>(new Tuna()));
vecOfFish.push_back(std::shared_ptr<Fish>(new Carp()));
 
 
 
> Which methods (copy constructor, copy assignment operator,....) must
> Carp and Tuna implement for the std::copy function to work properly
> (to perform a deep copy on my vector)?
 
For deep copy one needs to duplicate all the Tuna and Carp objects, given
only pointers to Fish. One typically implements this by declaring a
virtual clone function (look this up) in the base class. Both Carp and
Tuna must implement this and return a (smart)pointer to the cloned
object. The clone functions will typically make use of the copy
constructors.
 
std::copy() is probably not enough for getting deep copy (unless you use
a specific deep-copying smartpointer which does not seem very practical
otherwise). You will need to write a custom loop or use something like
std::transform().
 
hth
Paavo
Doug Mika <dougmmika@gmail.com>: Apr 20 09:35AM -0700

The definition of std::ifstream::open is as follows
(according to www.cplusplus.com & www.cppreference.com):
 
void open (const char* filename, ios_base::openmode mode = ios_base::in);
void open (const string& filename, ios_base::openmode mode = ios_base::in);
 
this means that both the open member functions take two parameters. HOWEVER, I can open a stream as follows:
 
ifstream inFile;
inFile.open("input.dat");
 
Why isn't the open member function that takes one parameter part of the www.cplusplus.com std::ifstream::open definition?
Victor Bazarov <v.bazarov@comcast.invalid>: Apr 20 12:52PM -0400

On 4/20/2015 12:35 PM, Doug Mika wrote:
 
> ifstream inFile;
> inFile.open("input.dat");
 
> Why isn't the open member function that takes one parameter part of the www.cplusplus.com std::ifstream::open definition?
 
Read up on default argument values.
 
V
--
I do not respond to top-posted replies, please don't ask
Doug Mika <dougmmika@gmail.com>: Apr 20 08:55AM -0700

The official definition of cin.get(cStr, n) is as follows:
 
std::istream::get
istream& get (char* s, streamsize n);
 
Does this mean that when we type
char someString[256];
cin.get(someString, 255);
 
we ignore the return type istream&?
Does this mean I could write:
cin = cin.get(someString,255);
What purpose does this return type serve?
Victor Bazarov <v.bazarov@comcast.invalid>: Apr 20 12:16PM -0400

On 4/20/2015 11:55 AM, Doug Mika wrote:
> Does this mean I could write:
> cin = cin.get(someString,255);
> What purpose does this return type serve?
 
The purpose is to allow chaining of function calls, like
 
cin.get(blah).get(blahblah)
 
or using it in an expression
 
cin.get(blah) >> somethingelse;
 
V
--
I do not respond to top-posted replies, please don't ask
Paavo Helde <myfirstname@osa.pri.ee>: Apr 20 11:21AM -0500

Doug Mika <dougmmika@gmail.com> wrote in news:2cab1a66-64b1-4b2f-b46d-
> Does this mean I could write:
> cin = cin.get(someString,255);
> What purpose does this return type serve?
 
This allows for call chaining, e.g.
 
cin.get(string1, 255).get(string2, 255).get(string3, 255);
Paul <pepstein5@gmail.com>: Apr 20 05:53AM -0700

Please can someone explain why the second version does not compile even though the first one does? The error is "no matching function for call to end(int*&)"
 
Thank you,
 
Paul
 
 
void testBeginEnd()
{
int a[] = {1, 2};
auto n = end(a) - begin(a);
}
 
void testBeginEnd(int a[] )
{
auto n = end(a) - begin(a);
}
Luca Risolia <luca.risolia@linux-projects.org>: Apr 20 03:07PM +0200

On 20/04/2015 14:53, Paul wrote:
> Please can someone explain why the second version does not compile even though the first one does? The error is "no matching function for call to end(int*&)"
 
because the array parameter "decays" into a pointer, for which there is
no matching end() function declared.
 
Juha Nieminen <nospam@thanks.invalid>: Apr 20 02:30PM

> int a[] = {1, 2};
> auto n = end(a) - begin(a);
> }
 
Here 'a' is a static array, not a pointer. Thus std::begin() and std::end()
work fine with it.
 
> {
> auto n = end(a) - begin(a);
> }
 
Here 'a' is a pointer, not a static array, thus they don't work with it.
 
The syntax you used doesn't mean "static array". It means "pointer".
To receive a static array as parameter you have to use a different
syntax:
 
void testBeginEnd(int (&a)[2])
 
(Although note that the entire array is not passed to the function,
but rather a reference to the original array.)
 
--- news://freenews.netfront.net/ - complaints: news@netfront.net ---
Victor Bazarov <v.bazarov@comcast.invalid>: Apr 20 10:45AM -0400

On 4/20/2015 10:30 AM, Juha Nieminen wrote:
 
> void testBeginEnd(int (&a)[2])
 
> (Although note that the entire array is not passed to the function,
> but rather a reference to the original array.)
 
Just a nit-pick... Neither in the former example, nor in the latter
declaration, the array is *static*. While severely overloaded, the term
'static' has nonetheless specific meaning that doesn't apply here, I think.
 
It is better to use the term "an array of a known dimension" instead of
"static array" in such explanations. In a declaration "foo(int a[])"
the argument is "an array of unknown dimension", which inturnally (a pun
on "in turn", he-he) is converted into a pointer, as you already pointed
out.
 
V
--
I do not respond to top-posted replies, please don't ask
peter koch <peter.koch.larsen@gmail.com>: Apr 20 01:44AM -0700

Søndag den 19. april 2015 kl. 01.31.38 UTC+2 skrev Victor Bazarov:
> On 4/18/2015 4:02 PM, Stefan Ram wrote:
[...]
 
> rather than
 
> T x{expression};
 
> For built-in types those mean the same thing.
 
Not quite. Consider:
 
int i = 3.14;
int i = { 3.14 };
 
The first one succeeds, where the second one gives a compiler error.
 
/Peter
Victor Bazarov <v.bazarov@comcast.invalid>: Apr 20 09:03AM -0400

On 4/20/2015 4:44 AM, peter koch wrote:
 
> int i = 3.14;
> int i = { 3.14 };
 
> The first one succeeds, where the second one gives a compiler error.
 
I am not sure why you have combined the two forms in the latter
statement and expect it to work. Shouldn't the comparison have been
 
int i = 3.14;
 
with
 
int i{3.14};
 
?
 
V
--
I do not respond to top-posted replies, please don't ask
peter koch <peter.koch.larsen@gmail.com>: Apr 20 07:14AM -0700

Mandag den 20. april 2015 kl. 15.03.36 UTC+2 skrev Victor Bazarov:
> On 4/20/2015 4:44 AM, peter koch wrote:
[snip]
 
> int i = 3.14;
 
> with
 
> int i{3.14};
 
Yup - you are right. The equal-sign was the result of an incorrect copy-paste.
 
/Peter
Ian Collins <ian-news@hotmail.com>: Apr 20 07:52PM +1200

Paavo Helde wrote:
> other temporary object [...]"
 
> So, as the array is temporary, a pointer to its element can and will
> become dangling as far as I can see.
 
I thought the clarification (making the return value a constexpr) takes
care of that. Certainly the generated code I've checked for a couple of
compilers shows the values being accessed from static data. For example
gcc -O3 -std=c++11 (or -O3 -std=c++14) compiles
 
 
int c();
 
int f()
{
const int* y = std::begin({ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
 
return y[c()];
}
 
as
 
_Z1fv:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
call _Z1cv
movl ._0(,%eax,4), %eax
leave
ret
 
where ._0 is
._0:
.long 1
.long 2
.long 3
.long 4
.long 5
.long 6
.long 7
.long 8
.long 9
.long 10
 
and
 
int f()
{
const int* y = std::begin({ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
 
return y[4];
}
 
as
 
_Z1fv:
movl $5, %eax
ret
 
:)
 
--
Ian Collins
Victor Bazarov <v.bazarov@comcast.invalid>: Apr 19 08:36PM -0400

On 4/19/2015 7:30 PM, Stefan Ram wrote:
 
> For example, define »make_unique« at the top of a
> translation unit with lines that only have this effect
> when make_unique is not already declared at this point?
 
There is probably a way to do it using SFINAE, by trying to take the
address of that function. If the function is not declared, taking the
address of it should be not possible, so the template is not going to be
generated... Then you could try to define your function as the member
of that template, or specialize it... Seems like a lot of work for no
obvious gain, though.
 
What problem are you trying to solve?
 
V
--
I do not respond to top-posted replies, please don't ask
Louis Krupp <lkrupp@nospam.pssw.com.invalid>: Apr 19 07:56PM -0600

On 19 Apr 2015 23:30:54 GMT, ram@zedat.fu-berlin.de (Stefan Ram)
wrote:
 
 
> For example, define »make_unique« at the top of a
> translation unit with lines that only have this effect
> when make_unique is not already declared at this point?
 
If you can depend on only C++14 implementations having make_unique,
then this page might be useful:
 
http://sourceforge.net/p/predef/wiki/Standards/
 
Louis
Paavo Helde <myfirstname@osa.pri.ee>: Apr 20 12:46AM -0500

ram@zedat.fu-berlin.de (Stefan Ram) wrote in news:make_unique-
 
> Some implementations do not already supply »make_unique«,
> so I thought about adding some lines at the top that define
> »make_unique« if it's not declared at this point.
 
This is typically done by a lot of preprocessor hackery. Here is a small
excerpt from such a hackery, meant for defining std::move when it is not
present. Such a mechanism provides a way to cope also with other mising
features, not only missing function definitions.
 
#ifdef __GNUC__
#define HAVE_COMPILER_GCC

No comments: