Constructor call

General discussion about C/C++

Moderators: Darobat, RecursiveS, Dante Shamest, Bugdude, Wizard

Constructor call

Postby netboy » Wed Oct 19, 2011 10:00 am

Why (1) shows an error and (2) does not?
The compile time error is request for member ‘print’ in ‘b’, which is of non-class type ‘ABC(XYZ (*)())’


(1)
#include <iostream>
using namespace std;

class XYZ
{
public:
XYZ()
{
cout << "const XYZ called";
}
};


class ABC
{

public:

ABC(XYZ xyz)
{
cout << "const ABC called";
}
void print()
{
}
};


int main()
{
ABC b(XYZ());
b.print();
}


(2)
#include <iostream>
using namespace std;

class XYZ
{
public:
XYZ()
{
cout << "const XYZ called";
}
};


class ABC
{

public:

ABC(int i, XYZ xyz)
{
cout << "const ABC called";
}
void print()
{
}
};


int main()
{
ABC b(1, XYZ());
b.print();
}
netboy
 
Posts: 5
Joined: Wed Oct 19, 2011 9:48 am

Re: Constructor call

Postby Wizard » Thu Oct 20, 2011 6:56 am

What's the error?
User avatar
Wizard
Site Admin
 
Posts: 3226
Joined: Mon Sep 22, 2003 4:52 pm
Location: ON, CA

Re: Constructor call

Postby netboy » Thu Oct 20, 2011 7:32 am

Wizard wrote:What's the error?


request for member ‘print’ in ‘b’, which is of non-class type ‘ABC(XYZ (*)())’
netboy
 
Posts: 5
Joined: Wed Oct 19, 2011 9:48 am

Re: Constructor call

Postby Wizard » Fri Oct 21, 2011 10:01 am

How strange. But if you say
Code: Select all
XYZ a;
ABC b(a);

the error disappears. Technically it should be the same whether called with a variable or anonymously, or so I'd think. It also goes away if you double wrap the inner function call, as so
Code: Select all
ABC b((XYZ()));

I honestly have no idea what part of the spec would lead to this, but it's consistent across multiple compilers so either I have to think it's in the spec or something that every compiler is consistently doing wrong: I'm guessing the former. If I were to make a wild guess, I'd say it had something to do with order of operation: the compiler doesn't see "ABC b(XYZ());" as creating an ABC named b with parameter XYZ(), but instead creating some kind of bizarre ABC(XYZ*) object, or something: in either case, the additional brackets explicitly tell the order of operation so it does what you expect.
Perhaps if Alvaro ever comes to visit again he might be able to shed some light on it; his brain is huge. In the meantime, don't call constructors like that, use the workaround of explicitly specifying a variable or double wrapping the constructor, I guess.
So weird. :wtf:
User avatar
Wizard
Site Admin
 
Posts: 3226
Joined: Mon Sep 22, 2003 4:52 pm
Location: ON, CA

Re: Constructor call

Postby netboy » Thu Oct 27, 2011 4:33 am

It also goes away if you double wrap the inner function call, as so

That was a new input, Thanks.

I'd say it had something to do with order of operation: the compiler doesn't see "ABC b(XYZ());" as creating an ABC named b with parameter XYZ(), but instead creating some kind of bizarre ABC(XYZ*) object, or something: in either case, the additional brackets explicitly tell the order of operation so it does what you expect.

Then why the compiler recognizes the statement ABC b(XYZ(1)), if the constructor is modified to XYZ(int i) ?
Why the compiler treats ABC b(XYZ()) and ABC b(XYZ(1)) differently?

The following are my findings, which are weird.
1. You can see that it doesn't even call XYZ(), by commenting b.print()
2. ABC b(XYZ(1)), by modifying the constructor XYZ(int i), also disappears the error.
3. Modifying the constructor to take ABC b(XYZ(), 1) also doesn't show the error.
4. The only issue is that XYZ() should not be the only argument.
5. I doubt that if the line ABC b(XYZ()) has any similarity with the copy constructor of ABC, which cause the error !!!

In the meantime, don't call constructors like that, use the workaround of explicitly specifying a variable

How ever, the call ABC b(XYZ()) is valid, as it is used to create a temporary object inside a function. If we create a variable outside and pass it, then this particular function will call the copy constructor.
netboy
 
Posts: 5
Joined: Wed Oct 19, 2011 9:48 am

Re: Constructor call

Postby schloob » Mon Oct 31, 2011 11:13 pm

I'm guessing that it thinks you tried to declare a function pointer.
:]
User avatar
schloob
 
Posts: 1853
Joined: Mon Feb 16, 2004 10:29 am
Location: Seattle

Re: Constructor call

Postby netboy » Tue Nov 01, 2011 10:33 am

schloob wrote:I'm guessing that it thinks you tried to declare a function pointer.


The answer to this issue is that the statement

ABC b(XYZ());

is not an object declaration. It is a function declaration, which is inherited from the C
Language. In this particular statement, it happens because the constructor XYZ() doesn't return anything.
So it is parsed by the C++ compiler as a function declaration with parameter type
XYZ(*)(). Thus b.print() will give an error as b is not an object and it is a function name.

The following modified statements are parsed by the C++ compiler as object declarations, as
they cannot be function declarations. So it calls the constructor XYZ(), explicitly.

ABC b((XYZ()));
ABC b(1, XYZ());
ABC b(XYZ(), 1);
ABC b(XYZ(1));

This type of constructor call is valid, as it is used to create a temporary object within a function.
netboy
 
Posts: 5
Joined: Wed Oct 19, 2011 9:48 am

Re: Constructor call

Postby Wizard » Tue Nov 01, 2011 3:08 pm

Oh neat. What a clever (albeit possibly confusing) thing to do. Thanks :)
User avatar
Wizard
Site Admin
 
Posts: 3226
Joined: Mon Sep 22, 2003 4:52 pm
Location: ON, CA

Re: Constructor call

Postby netboy » Tue Nov 01, 2011 7:42 pm

Wizard wrote:Oh neat. What a clever (albeit possibly confusing) thing to do. Thanks :)


Yes. The rule is check if it can be parsed as a function declaration, else parse as object declaration.

I have found this usage in the following command pattern example. But here it is properly used to create an object.
http://sourcemaking.com/design_patterns/command/cpp/2

Thanks for your replies.
netboy
 
Posts: 5
Joined: Wed Oct 19, 2011 9:48 am


Return to General

Who is online

Users browsing this forum: No registered users and 1 guest