Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

I don't understand how this code compiles.

85 views
Skip to first unread message

Chairman Mao

unread,
Oct 1, 2014, 5:32:17 AM10/1/14
to
I don't understand how this code compiles. For me, the function should be defined as `void f(const A::B& b)`, but g++ says that A::B is not a type.

struct A
{
struct B* p;
};

void f(const B& b )
{
}

int main()
{
A a;
f(*a.p);
}

Ian Collins

unread,
Oct 1, 2014, 6:47:12 AM10/1/14
to
Where is B declared?

--
Ian Collins

Chairman Mao

unread,
Oct 1, 2014, 6:57:59 AM10/1/14
to
I don't know. That's exactly the reason for my question.

Louis Krupp

unread,
Oct 1, 2014, 7:52:41 AM10/1/14
to
On Wed, 01 Oct 2014 23:46:57 +1300, Ian Collins <ian-...@hotmail.com>
wrote:
As far as I can tell, B is *declared* on the third line, when A.p is
defined as type struct B*, but B is never completely *defined*.


f(const B& b) is OK because it never actually *does* anything with its
argument.

Louis

Chairman Mao

unread,
Oct 1, 2014, 8:45:21 AM10/1/14
to
On Wednesday, October 1, 2014 8:52:41 AM UTC-3, Louis Krupp wrote:
> On Wed, 01 Oct 2014 23:46:57 +1300, Ian Collins <ian-news@****.com>
>
> wrote:
>
>
>
> >Chairman Mao wrote:
>
> >> I don't understand how this code compiles. For me, the function
>
> >> should be defined as `void f(const A::B& b)`, but g++ says that A::B
>
> >> is not a type.
>
> >>
>
> >> struct A { struct B* p; };
>
> >>
>
> >> void f(const B& b ) { }
>
> >>
>
> >> int main() { A a; f(*a.p); }
>
> >
>
> >Where is B declared?
>
>
>
> As far as I can tell, B is *declared* on the third line, when A.p is
>
> defined as type struct B*, but B is never completely *defined*.
>
>
>
>
>
> f(const B& b) is OK because it never actually *does* anything with its
>
> argument.
>
>
>
> Louis

I believe this has to with §3.3.2/6, but I can't see the exact relation between this paragraph and the code.

§3.3.2/6:

"The point of declaration of a class first declared in an elaborated-type-specifier is as follows:
-- for a declaration of the form class-key attribute-specifier-seqopt identifier;
the identifier is declared to be a class-name in the scope that contains the declaration, otherwise
-- for an elaborated-type-specifier of the form class-key identifier if the elaborated-type-specifier is used in the decl-specifier-seq or parameter-declaration-clause of a function defined in namespace scope, the identifier is declared as a class-name in the namespace that
contains the declaration; otherwise, except as a friend declaration, the identifier is declared in the smallest namespace or block scope that contains the declaration. [ Note: These rules also apply within templates. --end note ] [ Note: Other forms of elaborated-type-specifier do not declare a new name,
and therefore must refer to an existing type-name. See 3.4.4 and 7.1.6.3. --end note ]

Tobias Müller

unread,
Oct 1, 2014, 8:47:39 AM10/1/14
to
Chairman Mao <maotse3...@gmail.com> wrote:
> I don't understand how this code compiles. For me, the function should be
> defined as `void f(const A::B& b)`, but g++ says that A::B is not a type.
>
> struct A
> {
> struct B* p;
> };

B is only declared here, not defined.
That means you can define B* and B& variables but not variables of type B.

> void f(const B& b )
> {
> }

I didn't actually try this out but I'd say that B is not even visible at
that point. I'm not absolutely sure though.
const A::B& b would be clear.

> int main()
> {
> A a;
> f(*a.p);
> }

Here you dereference a B*, the result would have type B. This is not
allowed since B is only declared, but not defined.

Tobi

Tobias Müller

unread,
Oct 1, 2014, 8:57:51 AM10/1/14
to
Rereading the question, it seems that I completely missed the point.

Just speculating but could it be that 'struct B' is just a C-Style struct
label and does not actally declare a type A::B?

Tobi

Victor Bazarov

unread,
Oct 1, 2014, 9:30:24 AM10/1/14
to
By a brief examination of the relevant sections of the Standard I
couldn't divine whether an elaborate type specifier in a member
declaration would declare the type as a member of the class in which
such a declaration appears or as a member of the namespace... I am
guessing that the compiler implementers had similar difficulty and
decided that a type declaration in a member declaration creates a name
that is injected in the namespace scope (like a friend declaration would
do, for instance).

V
--
I do not respond to top-posted replies, please don't ask

Rick C. Hodgin

unread,
Oct 1, 2014, 10:02:01 AM10/1/14
to
Because struct B is not referenced by member anywhere, it is ignored
because it does not break the code anywhere. If you try to do something
with b in f(), or with a.p->..., then it will give you an error.

The only impact "struct B* p" will have in this is that it will occupy
4 bytes in the struct A allocation.

Best regards,
Rick C. Hodgin

Chairman Mao

unread,
Oct 1, 2014, 10:17:09 AM10/1/14
to
I think that's the answer. But when you say "the compiler implementers had similar difficulty" what are you talking about here? In other word, what would be the problem had the type, i.e., the elaborated-type-specifier been defined as a member of the class, instead of in the surrounding namespace?

Chairman Mao

unread,
Oct 1, 2014, 10:23:02 AM10/1/14
to
> I think that's the answer. But when you say "the compiler implementers had similar difficulty" what are you talking about here? In other words, what would be the problem had the type, i.e., the elaborated-type-specifier been declared as a member of the class, instead of in the surrounding namespace?

Victor Bazarov

unread,
Oct 1, 2014, 10:55:51 AM10/1/14
to
I meant the difficulty understanding the requirements of the Standard.

> In other word, what would be the problem had the type, i.e., the
> elaborated-type-specifier been defined as a member of the class,
> instead of in the surrounding namespace?

If the compiler were required to inject the name 'B' into the scope of
the class where it was first encountered, then the declaration of the
argument of the function 'f' would contain an unknown symbol 'B', making
your code ill-formed.

Paavo Helde

unread,
Oct 1, 2014, 12:22:37 PM10/1/14
to
Chairman Mao <maotse3...@gmail.com> wrote in
news:2bc4f5b1-aebf-42dd...@googlegroups.com:

> I don't understand how this code compiles. For me, the function should
> be defined as `void f(const A::B& b)`, but g++ says that A::B is not a
> type.
>
> struct A
> {
> struct B* p;
> };

This code also compiles in C, which has two consequences:

1. The code must compile in C++, for C compatibility.

2. Struct B cannot be A::B, because C does not have such a concept.

Thus, p here is bound to define a pointer to a top-level struct B. Probably
this is specified in some obscure back-alley in the standard.

Cheers
Paavo

Chairman Mao

unread,
Oct 1, 2014, 12:54:45 PM10/1/14
to
Of course, in this case the declaration of function `f` would be rewritten with `void f(const A::B&)` instead of `void f(const A&)`. But IMHO this alternative would be clearer for the user, than the one adopted by the implementers. I'm just wondering if there isn't some other stronger reason to inject the declaration of the elaborated-specifier-sequence in the surrounding namespace.

Rick C. Hodgin

unread,
Oct 1, 2014, 1:22:59 PM10/1/14
to
On Wednesday, October 1, 2014 12:54:45 PM UTC-4, Chairman Mao wrote:
> Of course, in this case the declaration of function 'f' would be rewritten
> with 'void f(const A::B&)' instead of 'void f(const A&)'.

I assume you mean 'void f(const B& b)'.

Why would you want it written as A::B? There is no reference to A in that
function. f() is designed to handle only B. It should have no knowledge
or requirement of A existing because it doesn't reference anything in A.

Chairman Mao

unread,
Oct 1, 2014, 1:27:56 PM10/1/14
to
Paavo, I think you have already answered my question about the decision the implementers have taken, by deciding to inject the elaborated-type-specifier in the surrounding namespace, instead of in the class (struct): compatibility with C. I'm pretty satisfied with the answers. Thanks to all and specially to Victor Bazarov and you for the valuable inputs.
0 new messages