Variable declaration or function prototype

A

Andrew Ward

Hi All,
Could someone please tell me why this code does not compile.

struct A {};

struct B {
B(A &) {}
};

struct C {
C(B &) {}
void f() {}
};

void foo() {
A a;
C c(B(a));
c.f();
}

If I change foo() to the following then it does compile:

void foo() {
A a;
B b(a);
C c(b);
c.f();
}

I would have thought that you could pass the B temporary into C's
constructor like that?

Andy
 
W

White Wolf

Andrew said:
Hi All,
Could someone please tell me why this code does not compile.

struct A {};

struct B {
B(A &) {}
};

struct C {
C(B &) {}
void f() {}
};

void foo() {
A a;
C c(B(a));
c.f();
}

If I change foo() to the following then it does compile:

void foo() {
A a;
B b(a);
C c(b);
c.f();
}

I would have thought that you could pass the B temporary into C's
constructor like that?

You could if you did write the constructors properly:

B(A const &);

C(B const &);

Temporaries cannot be bound to non-const references.
 
J

Jim Fischer

Andrew said:
Hi All,
Could someone please tell me why this code does not compile.

Unless I'm mistaken, the statement

C c(B(a));

is a function declaration (prototype). It declares a function named 'c'
that is passed (by value) a class B object, and returns (by value) a
class C object. This statement does not instantiate a class C object
named 'c'.
 
A

Andrew Ward

White Wolf said:
You could if you did write the constructors properly:

B(A const &);

C(B const &);

Temporaries cannot be bound to non-const references.

Even when I try passing by const & like you suggested it still does not
work, the error message is:

error C2228: left of '.f' must have class/struct/union type
type is 'overloaded-function'

Maybe Jim Fischer's suggestion is correct?

Andy
 
K

Kevin Goodsell

Andrew said:
Even when I try passing by const & like you suggested it still does not
work, the error message is:

error C2228: left of '.f' must have class/struct/union type
type is 'overloaded-function'

Maybe Jim Fischer's suggestion is correct?

In fact, they are both correct (I think). Attila's answer is what I
would have said. The problem Jim pointed out is a bit more insidious:

C c(B(a));

I don't know the exact rule, but basically because this *could* be
either a function declaration or an object instantiation, the former
wins. It's equivalent to

C c(B a);

With a pair of superfluous parenthesis.

-Kevin
 
J

Jim Fischer

Kevin said:
In fact, they are both correct (I think). Attila's answer is what I
would have said. The problem Jim pointed out is a bit more insidious:

C c(B(a));

I don't know the exact rule, but basically because this *could* be
either a function declaration or an object instantiation, the former
wins. It's equivalent to

C c(B a);

With a pair of superfluous parenthesis.

I'm 99.999% sure the statement 'C c(B(a));' is a function declaration
(see: 8.2/1 in ISO 14882:1998).

FWIW, you can disambiguate the interior subexpression 'B(a)' by wrapping
it in parens, e.g.,

C c( (B(a)) );

Now the compiler treats 'B(a)' as an object declaration that uses a
function-style type cast as the initializer (and not a function
declaration with a redundant set of parens around a parameter name).
IOW, 'B(a)' is now considered an invocation of B::B(A&). Consequently,
the surrounding expression - i.e., the declaration of 'c' - is also
treated as an object declaration with a function-style type cast as the
initializer.

Caveat: Making this change to your code introduces another problem.
Specifically, the unnamed, temporary class B object that results from
the invocation of B::B(A&) cannot be bound to a non-const reference. So
the construction of 'c' cannot occur because class C does not have a
suitable constructor - e.g., C::C(B&) cannot be used because B& is a
non-const reference. There are (at least) two fixes for this problem:

1) Modify the existing class C ctor

C(B &) { }

so its reference is const-valued

C(const B &) { }

or,

2) Add a second ctor to class C; one with a suitable const reference
argument:

class C {
C (B &) { }
C (const B &) { }
void f () { }
}
 
W

White Wolf

Andrew Ward wrote:
[SNIP]
Even when I try passing by const & like you suggested it still does
not work, the error message is:

error C2228: left of '.f' must have class/struct/union type
type is 'overloaded-function'

Maybe Jim Fischer's suggestion is correct?

Not maybe. :) Definitely. I am ashamed not seeing it - especially because
I have got my copy - of the book mentioning this "gotcha" - signed by the
author. Well, well well. Time for me to look for a job where no brains are
required. :)
 

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,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top