compilation error with direct-initialization

  • Thread starter subramanian100in
  • Start date
S

subramanian100in

Consider the following program x.cpp:

#include <cstdlib>
#include <iostream>
#include <vector>
#include <deque>
#include <string>

using namespace std;

template <typename Container>
typename Container::value_type add(const Container& c)
{
typename Container::value_type val = typename
Container::value_type();
// typename Container::value_type val(typename
Container::value_type());

for (typename Container::const_iterator ci = c.begin();
ci != c.end();
++ci)
val = val + *ci;

return val;
}

int main()
{
vector<int> c;
int i;

while (cin >> i)
c.push_back(i);

cout << "sum = " << add(c) << endl;

deque<string> d;
string str;

cin.clear();

while (cin >> str)
d.push_back(str + " ");

cout << "sum = " << add(d) << endl;

return EXIT_SUCCESS;
}

I compiled this program with g++3.4.3 as
g++ -std=c++98 -pedantic -Wall -Wextra x.cpp

There is no compilation error.

The line
typename Container::value_type val = typename Container::value_type();
is copy-initialization. Am I correct ?

Instead of the above line, if I have the following line
typename Container::value_type val(typename Container::value_type());

I get compilation error. I tried this form to behave as direct-
initialization. Isn't this direct-initialization ?

Kindly explain what is wrong with direct-initialization syntax?

Alternatively I could have used the prototype,
template <typename Container>
typename Container::value_type add(const Container& c,
typename
Container::value_type val)
to avoid declaring 'val' inside the function. But I didn't do it for
learning purpose only.

Thanks
V.Subramanian
 
R

Rolf Magnus

The line
typename Container::value_type val = typename Container::value_type();
is copy-initialization. Am I correct ?
Yes.

Instead of the above line, if I have the following line
typename Container::value_type val(typename Container::value_type());

I get compilation error. I tried this form to behave as direct-
initialization. Isn't this direct-initialization ?

No. It's the declaration of a function called 'val' that has a parameter of
type Container::value_type and also returns an object of that type.
 
B

Balog Pal

The line
typename Container::value_type val = typename Container::value_type();
is copy-initialization. Am I correct ?

Instead of the above line, if I have the following line
typename Container::value_type val(typename Container::value_type());

I get compilation error. I tried this form to behave as direct-
initialization. Isn't this direct-initialization ?

Direct init, but using the copy ctor still, and getting a copy... what is
this good for, instead of a really direct init:

typename Container::value_type val;

that would do the same?
 
S

subramanian100in

Suppose 'Test' is class with the default ctor and copy ctor defined

Then the line

Test obj(Test);

declares obj to be a function taking 'Test' class object as parameter
and returns a 'Test' class object. Am I correct ?

Now consider the line

Test obj(Test());

Here, I thought, Test() would return a temporary 'Test' class object
which would be the argument to copy ctor, that will create 'obj'.

Kindly explain me where I am misunderstanding.

What is the difference between the above two declarations ?

Thanks
V.Subramanian
 
S

SG

Suppose 'Test' is class with the default ctor and copy ctor defined

Then the line

Test obj(Test);

declares obj to be a function taking 'Test' class object as parameter
and returns a 'Test' class object. Am I correct ?

Now consider the line

Test obj(Test());

Here, I thought, Test() would return a temporary 'Test' class object
which would be the argument to copy ctor, that will create 'obj'.

The other interpretation would be that it's equivalent to

Test obj(Test(*)());

which decalres a function obj that takes a function pointer.
Kindly explain me where I am misunderstanding.
What is the difference between the above two declarations ?

See
http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=439

I would write

Test obj = Test();

instead for improved clarity and expect compilers to elide unnecessary
copies.

Cheers!
SG
 
B

Balog Pal

Balog Pal said:
Direct init, but using the copy ctor still, and getting a copy... what is
this good for, instead of a really direct init:

typename Container::value_type val;

that would do the same?

Self-correction: it differs in 'value-init', if the thing does not have a
declared ctor... So as the other people said, better use the = form, or you
may try to add extra sets of () to go around the 'can be read as
declaration' problem.
 
A

Alf P. Steinbach

* SG:
The other interpretation would be that it's equivalent to

Test obj(Test(*)());

which decalres a function obj that takes a function pointer.


See
http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=439

I would write

Test obj = Test();

instead for improved clarity and expect compilers to elide unnecessary
copies.

I agree, but just to not let some avenue be unexplored I just now tried
replacing all such in the code I'm working on (it's a small hobby project, so
far some 7K lines) with

Test obj (( value ));

I wasn't sure whether this notation is supported by formal argument default
initialization; it turned out that it's not.

Nor is it supported by the possible declarations in 'if' and loop heads.

I also discovered that, not counting for loop control variables, I have *very*
few local variables (and no global ones), perhaps one per 20th routine.

And this notation, as an adopted convention, sucketh a little for multi-argument
constructor, then necessitating something like

Test obj (( Test( a, b ) ));

although there was only one such declaration in the code.

But I think, for those who adopt the direct initialization notation as default
convention, as reportedly Francis Glasborrow does in his books, then (( ... ))
would be a nice convention for that, avoiding the "most vexing parse" problem
and reinstating some of the ease of visual recognition that "=" notation has.


Cheers,

- Alf
 
J

James Kanze


Which, of course, doesn't work if the object type doesn't
support copy. (In the particular case where the argument is
Test(), of course, the above doesn't work either if copy isn't
supported. And the above would normally be written just:
Test obj ;
..)
I agree, but just to not let some avenue be unexplored I just
now tried replacing all such in the code I'm working on (it's
a small hobby project, so far some 7K lines) with
Test obj (( value ));
I wasn't sure whether this notation is supported by formal
argument default initialization; it turned out that it's not.

It's probably the most general solution (since it works even for
objects which don't support copy). It's the one I usually use.
Nor is it supported by the possible declarations in 'if' and
loop heads.

No. You can't use objects which don't support copy in
conditionals. (The possibility of such declarations a
misfeature anyway, only useful for obfuscation.)

You can use direct initialization for the loop control variable
in the first part of a for statement, i.e.:
for ( Test obj( (value) ) ; // ...
I also discovered that, not counting for loop control
variables, I have *very* few local variables (and no global
ones), perhaps one per 20th routine.

Really:). (Function parameters are "local variables":).)
And this notation, as an adopted convention, sucketh a little
for multi-argument constructor, then necessitating something
like
Test obj (( Test( a, b ) ));

What's wrong with:
Test obj( (a), (b) ) ;
although there was only one such declaration in the code.

I have a couple. Mostly initialization of standard containers,
e.g.:

std::vector< Line > v( (std::istream_iterator< Line >( in )),
(std::istream_iterator< Line >()) ) ;
or

std::map< std::string, std::string > const
m( (begin( initTable )), (end( initTable )) ) ;

(where initTable is defined as:
struct InitMap
{
typedef std::map< std::string, std::string >::value_type
ValueType ;
char const* key ;
char const* value ;
operator ValueType() const
{
return ValueType( key, value ) ;
}
} ;
InitMap cosnt initTable[] =
{
{ "firstEntry" , "firstValue" },
{ "secondEntry", "secondValue" },
// ...
} ;
and begin and end in the usual way.)

Note that this is the only way (at least that I know) to create
a const instance of the container which isn't empty. (And no,
the extra parentheses aren't necessary for the example with
std::map, because begin and end aren't types. I don't usually
use it, but since I think you were talking about doing something
systematically.) In my code base, I've got a couple of cases
where I use const std::map.
But I think, for those who adopt the direct initialization
notation as default convention, as reportedly Francis
Glasborrow does in his books, then (( ... )) would be a nice
convention for that, avoiding the "most vexing parse" problem
and reinstating some of the ease of visual recognition that
"=" notation has.

Yes. I tend to favor direct initialization for class types; I'm
a lot less rigorous about it for other types. The main reason
is because it isn't assignment, and the = looks so much like an
assignment operator. (And the reason I'm less concerned about
this distinction with non-class types is because it doesn't
really exist for non-class types.)
 
S

SG

Which, of course, doesn't work if the object type doesn't
support copy.

Which of course, isn't the case here when the OP tries to return this
object by value.

Cheers!
SG
 
S

subramanian100in

I have a doubt in the same program I posted originally in the
beginning of this thread.
Kindly bear with me.

To avoid declaring 'val' inside the function add(), I could have
written,
template <typename Container>
typename Container::value_type add(const Container& c,
typename Container::value_type val)

But for the sake of learning purpose only, suppose I do not use this
prototype.

Consider the following program x.cpp:

#include <cstdlib>
#include <iostream>
#include <vector>
#include <deque>
#include <string>

using namespace std;

template <typename Container>
typename Container::value_type add(const Container& c)
{
typename Container::value_type val =
typename Container::value_type();
/* typename Container::value_type val(
typename Container::value_type());
*/

for (typename Container::const_iterator ci = c.begin();
ci != c.end();
++ci)
val = val + *ci;

return val;

}

int main()
{
vector<int> c;
int i;

while (cin >> i)
c.push_back(i);

cout << "sum = " << add(c) << endl;

deque<string> d;
string str;

cin.clear();

while (cin >> str)
d.push_back(str + " ");

cout << "sum = " << add(d) << endl;

return EXIT_SUCCESS;

}

I compiled this program with g++3.4.3 as
g++ -std=c++98 -pedantic -Wall -Wextra x.cpp

There is no compilation error.

Suppose I want to call the function add() on a container with value-
type being a built-in type(as with the case vector<int> c;) as well a
class type (as with the case deque<string> d;).

Then I need to initialize the 'val' variable with an appropriate
default value because I am calculating

val = val + *ci;

I want to initialize 'val' with zero for built-in type argument to the
container and I want to call the default ctor for class type argument
to the container.

I cannot just write
typename Container::value_type val;
because, for built-in type for Container::value_type, this statement
will initialize 'val' with some garbage value.

So, I have to write
typename Container::value_type val = typename Container::value_type();

But for Container::value_type being class type, the above statement
performs copy-initialization. Copy-initialization MAY involve one copy
ctor. Is it possible to avoid this copy-initialization but at the same
time initialize 'val' to a default value of appropriate type - that
is, is there a syntax by which I can initialize 'val' directly for
Container::value_type being built-in type as well as class-type ? Or,
is the above original statement the only way(which means that copy-
initialization cannot be avoided at all times)?

Kindly explain.

Thanks
V.Subramanian
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,066
Latest member
VytoKetoReviews

Latest Threads

Top