Why doesn't this compile....?

F

fungus

I've got a base class foo:

class foo {
....
};


And a derived class foo_d:

class foo_d : public foo {
};


I then make another class which takes a foo
in the constructor:

class bar {
public:
bar(foo&);
};


All easy stuff... but when I try this the compiler
complains:

bar b(foo_d());

OTOH this is ok:

foo_d f;
bar b(f);

Why...?



--
<\___/>
/ O O \
\_____/ FTB. For email, remove my socks.

In science it often happens that scientists say, 'You know
that's a really good argument; my position is mistaken,'
and then they actually change their minds and you never
hear that old view from them again. They really do it.
It doesn't happen as often as it should, because scientists
are human and change is sometimes painful. But it happens
every day. I cannot recall the last time something like
that happened in politics or religion.

- Carl Sagan, 1987 CSICOP keynote address
 
J

Jakob Bieling

fungus said:
class foo {
...
};
class foo_d : public foo {
};
class bar {
public:
bar(foo&);
};
complains:

bar b(foo_d());

OTOH this is ok:

foo_d f;
bar b(f);

Why...?

In the first case, you create a temporary 'foo_d' object and want to
pass this to the ctor of 'bar'. The problem is, that temporaries can
only be bound to _const_ references. But the 'bar' ctor takes a
non-const reference. In the second case you do not have this problem,
because there is no temporary.

You can fix this by changing the constructor of 'bar' to take a
'foo_d const&'.


hth
 
R

Ron Natalie

fungus said:
All easy stuff... but when I try this the compiler
complains:

bar b(foo_d());

OTOH this is ok:

foo_d f;
bar b(f);

Why...?
You can't bind rvalues to non-const references.
Make the constructor
bar(const foo&);
 
F

fungus

Jakob said:
You can fix this by changing the constructor of 'bar' to take a
'foo_d const&'.

I thought of that.... but when I try it I get a
different error:

test.cpp: error: ‘foo::foo(const foo&)’ is private
In constructor ‘bar::bar()’
warning: synthesized method ‘foo_d::foo_d(const foo_d&)’
first required here


(and yes, foo::foo(const foo&) is declared private...)


--
<\___/>
/ O O \
\_____/ FTB. For email, remove my socks.

In science it often happens that scientists say, 'You know
that's a really good argument; my position is mistaken,'
and then they actually change their minds and you never
hear that old view from them again. They really do it.
It doesn't happen as often as it should, because scientists
are human and change is sometimes painful. But it happens
every day. I cannot recall the last time something like
that happened in politics or religion.

- Carl Sagan, 1987 CSICOP keynote address
 
F

fungus

Ron said:
It must be public to use it from outside the class.

It's private for a reason...

The point is that the copy constructor
shouldn't even be called...I'm passing
a reference!



--
<\___/>
/ O O \
\_____/ FTB. For email, remove my socks.

In science it often happens that scientists say, 'You know
that's a really good argument; my position is mistaken,'
and then they actually change their minds and you never
hear that old view from them again. They really do it.
It doesn't happen as often as it should, because scientists
are human and change is sometimes painful. But it happens
every day. I cannot recall the last time something like
that happened in politics or religion.

- Carl Sagan, 1987 CSICOP keynote address
 
A

Alf P. Steinbach

* fungus:
It's private for a reason...

The point is that the copy constructor
shouldn't even be called...I'm passing
a reference!

When passing a temporary to 'T const&' argument, the copy constructor
must be available, and it can be (but usually isn't) called.

One workaround is to provide a conversion to 'T const&'.

AFAIK nobody has come up with any reason why that could be undesirable,
but OTOH, AFAIK nobody actually uses this technique, so I make no
recommendation.
 
K

Kai-Uwe Bux

Alf said:
* fungus:

When passing a temporary to 'T const&' argument, the copy constructor
must be available, and it can be (but usually isn't) called.

One workaround is to provide a conversion to 'T const&'.

AFAIK nobody has come up with any reason why that could be undesirable,
but OTOH, AFAIK nobody actually uses this technique, so I make no
recommendation.

Are you sure about the conversion function?

12.3.2/1:
... A conversion function is never used to convert a (possibly
cv-qualified) object to the (possibly cv-qualified) same object type (or a
reference to it), to a (possibly cv-qualified) base class of that type (or
a reference to it), or to (possibly cv-qualified) void.103)

103) Even though never directly called to perform a conversion, such
conversion functions can be declared and can potentially be reached
through a call to a virtual conversion function in a base class.


Or did you mean just an ordinary member like:

foo const & self ( void ) const {
return ( *this );
}



Best

Kai-Uwe Bux
 
A

Alf P. Steinbach

* Kai-Uwe Bux:
Alf said:
* fungus:
When passing a temporary to 'T const&' argument, the copy constructor
must be available, and it can be (but usually isn't) called.

One workaround is to provide a conversion to 'T const&'.

AFAIK nobody has come up with any reason why that could be undesirable,
but OTOH, AFAIK nobody actually uses this technique, so I make no
recommendation.

Are you sure about the [implicit] conversion function?

No, I was not sure about the implicit variant, I thought that was what I
wrote... ;-)

It was discussed in clc++m in connection with boost::noncopyable (or
whatever that class is called).

But as I recall nobody came up with:
12.3.2/1:
... A conversion function is never used to convert a (possibly
cv-qualified) object to the (possibly cv-qualified) same object type (or a
reference to it), to a (possibly cv-qualified) base class of that type (or
a reference to it), or to (possibly cv-qualified) void.103)

103) Even though never directly called to perform a conversion, such
conversion functions can be declared and can potentially be reached
through a call to a virtual conversion function in a base class.

Or did you mean just an ordinary member like:

foo const & self ( void ) const {
return ( *this );
}

I think that's the best solution, although I'd call it 'ref', and leave
out the C style void argument spec. :)

Checking how compilers treat the /implicit/ conversion operator, MSVC
7.1 ignores it and the lack of accessible copy constructor, because
already C++0x compliant (heh! -- it's just a bug that happens to
coincide with anticipated change of the standard); g++ 3.4.4 invokes the
operator; and Comeau Online 4.3.3 produces first a warning that it will
never be used, and then an error on the attempted usage.
 
O

Old Wolf

This code declares a function 'b', returning 'bar' and taking
one argument: a pointer to function taking no arguments and
returning 'foo_d'.

It doesn't declare an object.

This code by itself won't generate an error, but you will get
errors if you then try and use 'b' as if it were an object.

You could avoid this problem by writing:
bar b((foo_d()));

(there are other workarounds available too).
I thought of that.... but when I try it I get a
different error:

test.cpp: error: 'foo::foo(const foo&)' is private
In constructor 'bar::bar()'
warning: synthesized method 'foo_d::foo_d(const foo_d&)'
first required here
(and yes, foo::foo(const foo&) is declared private...)

You must have some code you didn't show us (at a guess,
does foo_d actually have a parameter to the constructor?)

If you did in fact write:
bar b((foo_d()));
or
bar b(foo_d(3)); // with appropriate foo_d constructor

you would get this error.

In this case, the error is because in order to bind a temporary
object to a reference to const, the temporary object must have
a publicly accessible copy-constructor.

That code should work, without the need for a public
copy constructor. What error does it give you?
 
F

fungus

Alf said:
When passing a temporary to 'T const&' argument, the copy constructor
must be available, and it can be (but usually isn't) called.

That seems unnecessary to me...
One workaround is to provide a conversion to 'T const&'.

I can live with writing the code in two lines
I was just curious why it didn't work.
AFAIK nobody has come up with any reason why that could be undesirable,
but OTOH, AFAIK nobody actually uses this technique, so I make no
recommendation.

I used it!

I'm currently porting a program from VC++ to G++
and it broke some code. My base class foo had an
operator bool() defined and the compiler was calling
the wrong constructor when it created the "bar"
(bar also has an integer constructor).


--
<\___/>
/ O O \
\_____/ FTB. For email, remove my socks.

In science it often happens that scientists say, 'You know
that's a really good argument; my position is mistaken,'
and then they actually change their minds and you never
hear that old view from them again. They really do it.
It doesn't happen as often as it should, because scientists
are human and change is sometimes painful. But it happens
every day. I cannot recall the last time something like
that happened in politics or religion.

- Carl Sagan, 1987 CSICOP keynote address
 
I

Ian Collins

fungus said:
I'm currently porting a program from VC++ to G++
and it broke some code. My base class foo had an
operator bool() defined and the compiler was calling
the wrong constructor when it created the "bar"
(bar also has an integer constructor).
Get rid of it before it turns round and bites you.
 
F

fungus

Ian said:
My base class foo had an
Get rid of it before it turns round and bites you.

I did. I've recently come to the conclusion
that "operator bool()" is a bug waiting to
happen. I now do "bool ok() const;"



--
<\___/>
/ O O \
\_____/ FTB. For email, remove my socks.

In science it often happens that scientists say, 'You know
that's a really good argument; my position is mistaken,'
and then they actually change their minds and you never
hear that old view from them again. They really do it.
It doesn't happen as often as it should, because scientists
are human and change is sometimes painful. But it happens
every day. I cannot recall the last time something like
that happened in politics or religion.

- Carl Sagan, 1987 CSICOP keynote address
 
I

Ian Collins

fungus said:
I did. I've recently come to the conclusion
that "operator bool()" is a bug waiting to
happen. I now do "bool ok() const;"
Good. This should be embossed in the biggest font that will fit on the
first page of all C++ books.
 
S

ssb

My guess is because the function expects a reference to an object, and
you are actually passing an object, not a reference. The function
strictly expects a reference to foo.

OTOH, the second trial is correct, because you ARE passing a reference
to an object.
 

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,774
Messages
2,569,596
Members
45,142
Latest member
DewittMill
Top