Board index » cppbuilder » Re: scope (my summary)

Re: scope (my summary)


2007-10-24 09:52:49 PM
cppbuilder33
Leo Siefert < XXXX@XXXXX.COM >wrote:
Quote
Thanks for doing the footwork and providing the reference.

I suggest that you look at Fraser's most recent posting to this thread
with code that errs in the CodeGear compiler but passes Comeau.
The original "scope" thread became a little bit complicated to
follow, so I would like to summarize my findings here:
1) The answer to the original question "Is a publicly
inherited class name injected into the scope of the inheriting
class?" is definitely: NO
(C++ ISO standard (mainly chapter 3.4.3 Qualified name lookup
and 10.2. Member name lookup)
Example:
class A { public: int a; };
class B : public A { public: int a; };
class C : public B { public: int a;
void fn()
{
B::A::a = 1; // error. name A is not in
// the scope of B
A::a = 2; // ok. name A is in the global scope.
}
};
2) How to solve the ambiguity in the examples?
I can solve it only with a static cast of "this".
See example that compiles in BCB2006:
Example:
class A { public: int a; };
class B1 : public A { public: int a; };
class B2 : public A { public: int a; };
class C : public B1, public B2
{
public:
int a;
void fn()
{
a = 1; // ok
B1::a = 2; // ok
B2::a = 3; // ok
A::a = 4; // error: "'A' is not an unambiguous
// base class of 'C'"
B1::A::a = 4; // error: "Qualifier 'A' is not a
// class or namespace name"
// According to C++ Standard name A
// exists in the global scope not in
// the scope of B1.
static_cast<B1 *>(this)->a = 4;
// ok. set A::a copy in B1
static_cast<B2 *>(this)->a = 5;
// ok. set A::a copy in B2
}
};
This makes me say: BCB2006 complies with the ISO C++ Standard
in this case.
Vaclav
 
 

Re:Re: scope (my summary)

Vaclav Cechura wrote:
Quote
Example:
class A { public: int a; };
class B1 : public A { public: int a; };
class B2 : public A { public: int a; };
class C : public B1, public B2
...
static_cast<B1 *>(this)->a = 4;
// ok. set A::a copy in B1
You lose me here, how and why does that access the A::a inside B1 and
not the a of B1 itself?
-Eliot
 

Re:Re: scope (my summary)

Vaclav Cechura wrote:
Quote
Example:
class A { public: int a; };
class B1 : public A { public: int a; };
class B2 : public A { public: int a; };
class C : public B1, public B2
static_cast<B1 *>(this)->a = 4;
// ok. set A::a copy in B1
static_cast<B2 *>(this)->a = 5;
// ok. set A::a copy in B2
Ok I tested it. The way you wrote it, these lines only access the
int a; inside of B1 and B2 respectively not the int a; inside the base
class A.
You meant to write,
static_cast<B1 *>(this)->A::a = 4;
// ok. set A::a copy in B1
static_cast<B2 *>(this)->A::a = 5;
// ok. set A::a copy in B2
Which does compile and work the way you wanted.
-Eliot
 

{smallsort}

Re:Re: scope (my summary)

Eliot Frank < XXXX@XXXXX.COM >wrote:
Quote
Ok I tested it. The way you wrote it, these lines only access the
int a; inside of B1 and B2 respectively not the int a; inside the base
class A.

You meant to write,

static_cast<B1 *>(this)->A::a = 4;
// ok. set A::a copy in B1
static_cast<B2 *>(this)->A::a = 5;
// ok. set A::a copy in B2

Which does compile and work the way you wanted.
Thank you for correcting my post.
I totally forgot the 'a' members I declared inside of classes
B1 and B2 that hid the 'a' member of class A.
Vaclav
 

Re:Re: scope (my summary)

"Vaclav Cechura" < XXXX@XXXXX.COM >wrote:
Quote
I totally forgot the 'a' members I declared inside of classes
B1 and B2 that hid the 'a' member of class A.
The whole design is deeply odd, anyway. The problem is that the B1/B2
classes have been deliberately written to hide the A members, and you're
now trying to unhide them.
Alan Bellingham
--
Team Browns
ACCU Conference 2008: 2-5 April 2008 - Oxford (probably), UK
 

Re:Re: scope (my summary)

Alan Bellingham wrote:
Quote
The whole design is deeply odd, anyway. The problem is that the
B1/B2 classes have been deliberately written to hide the A members,
and you're now trying to unhide them.
True. I think the original code is written to explore an issue and to
possibly uncover compiler errors. Sometimes a blatantly contrived
example helps a user to better see the way things work and can help
clarify a problem in real code. At least I hope that is the case here.
- Leo
 

Re:Re: scope (my summary)

Leo Siefert < XXXX@XXXXX.COM >writes:
Quote
Alan Bellingham wrote:

>The whole design is deeply odd, anyway. The problem is that the
>B1/B2 classes have been deliberately written to hide the A members,
>and you're now trying to unhide them.

True. I think the original code is written to explore an issue and to
possibly uncover compiler errors. Sometimes a blatantly contrived
example helps a user to better see the way things work and can help
clarify a problem in real code. At least I hope that is the case here.
I remember back in the mid 90's my first post to these Borland groups.
I was getting an internal compiler error on our production application
(which I was trying to port to Borland in my free time) and I spent
2-3 hours stripping it down to a 10-line program that reproduced the
ICE.
The resulting code was extremely contrived-looking, because I removed
the interesting (but unrelated) code, and was left with ... not much.
I posted it, and the response I got was a bit surprising. I was told
how to "fix" my code so that the bug wouldn't happen, I was told that
my code was ridiculous and that empty constructors weren't necessary,
and I was politely ignored. However, the fact remained that the
compiler crashed on my code, and not one person (on the newsgroups at
least) seemed to think that mattered--but me.
Things have changed a lot since then. :)
--
Chris (TeamB);
 

Re:Re: scope (my summary)

"Vaclav Cechura"
Quote
(C++ ISO standard (mainly chapter 3.4.3 Qualified name lookup
and 10.2. Member name lookup)

Example:
class A { public: int a; };
class B : public A { public: int a; };
class C : public B { public: int a;
void fn()
{
B::A::a = 1; // error. name A is not in
// the scope of B
A::a = 2; // ok. name A is in the global scope.
}
};
Your wrong with the first comment. 'Class name injection' and the
public inheritance of A are the reasons why "B::A::" is acceptable in C.
If you've got the book C++ Templates there is a couple of pages on it at
section 9.2.3. I don't think there is a QC report which I suggested
making.
Fraser.
 

Re:Re: scope (my summary)

The focus of the groups both then and now are first and foremost to get the
poster up and running. That does not mean that the bug was not reported,
just that the fact of it being reported was not relayed to you.
. Ed
Quote
Chris Uzdavinis wrote in message
news: XXXX@XXXXX.COM ...

...The resulting code was extremely contrived-looking, because I
removed the interesting (but unrelated) code, ...

I posted it, and the response I got was a bit surprising. I was told
how to "fix" my code so that the bug wouldn't happen...
 

Re:Re: scope (my summary)

"Ed Mulroy [TeamB]" < XXXX@XXXXX.COM >writes:
Quote
The focus of the groups both then and now are first and foremost to
get the poster up and running. That does not mean that the bug was
not reported, just that the fact of it being reported was not
relayed to you.
The overall feeling I got was that of indifference and the lack of
understanding of what I was even trying to post. I was very clear in
that I knew how to change my code to make it compile (I even included
comments indicating what had to be there, which, if removed, didn't
reproduce the ICE.) It should have been obvious to anyone reading it
that I wasn't asking for help getting the code to "run", but was
reporting a real-world ICE, which at the time I thought would be taken
seriously.
(There was no QC back then.)
--
Chris (TeamB);
 

Re:Re: scope (my summary)

"Fraser Ross" < XXXX@XXXXX.COM >wrote:
Quote
Your wrong with the first comment. 'Class name injection' and the
public inheritance of A are the reasons why "B::A::" is acceptable in C.
ISO C++ Standard:
"Multiply qualified names, such as N1::N2::N3::n, can be used
to refer to members of nested classes (9.7) or members of
nested namespace."
The whole ISO C++ Standard mentions the word injection only
twice. It's in the section 11.2. Nested classes in this example:
class C {
class A { };
A *p; // OK
class B : A // OK
{
A *q; // OK because of injection of name A in A
C::A *r; // error, C::A is inaccessible
B *s; // OK because of injection of name B in B
C::B *t; // error, C::B is inaccessible
};
};
which demonstrates that a class name is injected in the scope
of the same class.
Quote
If you've got the book C++ Templates there is a couple of pages on it at
section 9.2.3.
I was talking about the C++ ISO Standars and I found nothing
about class name injection into inherited classes scope there.
Vaclav
 

Re:Re: scope (my summary)

Alan Bellingham < XXXX@XXXXX.COM >wrote:
Quote
"Vaclav Cechura" < XXXX@XXXXX.COM >wrote:
The whole design is deeply odd, anyway. The problem is that the B1/B2
classes have been deliberately written to hide the A members, and you're
now trying to unhide them.
I would say the whole problem is deeply odd and slightly
artificial from the beginning. But I did not invent it. I was
only trying to answer the original question regarding 'class
name injection'.
The problem was not how to unhide the A::a members, but how to
disambiguate the two copies of A::a inherited in C through
B1 and B2 in the schema:
class A { public: int a; }
class B1 : public A { public: int a; }
class B2 : public A { public: int a; }
class C : public B1, public B2
{ public: int a; }
Unless there are 'a' members defined in B1 and B2, B1::a and
B2::a would refer to the inherited A::a members.
The OP was suggesting that Borland copiler falsely detects
an error in the expression C::B1::A::a. But according to
my findings this code is valid only with nested classes or
namespaces. This is what I was demonstrating.
Vaclav
 

Re:Re: scope (my summary)

"Vaclav Cecura" < XXXX@XXXXX.COM >wrote:
Quote
The whole ISO C++ Standard mentions the word injection only
twice. It's in the section 11.2. Nested classes in this example:
There are other 14 occurencies of the term injected-class-name
in the ISO C++ Standard all of them reffering to a class/class
template name being injected in the scope of the same class/
class template.
Vaclav
 

Re:Re: scope (my summary)

"Vaclav Cecura"
Quote
I was talking about the C++ ISO Standars and I found nothing
about class name injection into inherited classes scope there.
I've understood that that isn't done since the 22nd, 3 days ago now. I
could have made it clearer that I understood now.
In your program above B::A::a = 1; is compileable code for the reasons I
gave and it compiles with Comeau.
Fraser.
 

Re:Re: scope (my summary)

"Fraser Ross" < XXXX@XXXXX.COM >writes:
Quote
"Vaclav Cechura"
>(C++ ISO standard (mainly chapter 3.4.3 Qualified name lookup
>and 10.2. Member name lookup)
>
>Example:
>class A { public: int a; };
>class B : public A { public: int a; };
>class C : public B { public: int a;
>void fn()
>{
>B::A::a = 1; // error. name A is not in
>// the scope of B
>A::a = 2; // ok. name A is in the global scope.
>}
>};
Your wrong with the first comment. 'Class name injection' and the
public inheritance of A are the reasons why "B::A::" is acceptable in C.
If you've got the book C++ Templates there is a couple of pages on it at
section 9.2.3. I don't think there is a QC report which I suggested
making.
I think this conversation is drifting onto a tangent.
It's valid to say B::A::a. However, it's not a viable solution to the
multiple-inheritance situation because scope-resolution operator (::)
is simply a way to find a single type. That is, it doesn't give a
path-hint to the compile for which base we're referring to, but just a
path to FIND a single type, isolated type. Once it found the type
(A), it doesn't care how it got it, or which path it took to get
there. It could be a typedef inside a template class with T being A,
for all it cares. Once found, it simply refers to one class type, A.
At that point, it evaluates all the possible paths to find the name,
and it realizes that there are multiple A bases, and so the call is
ambiguous.
--
Chris (TeamB);