Topic: Implicit class member access
Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Sat, 6 Feb 2010 12:04:59 CST Raw View
The last example has another interesting side. Can anybody explain how
the wordings in N3000 - 9.3.1/3
"When an id-expression (5.1) that is not part of a class member access
syntax (5.2.5) and not used to form a pointer to member (5.3.1) is
used in the body of a non-static member function of class X, if name
lookup (3.4.1) resolves the name in the id-expression to a non-static
non-type member of some class C, the id-expression is transformed into
a class member access expression (5.2.5) using (*this) (9.3.2) as the
postfix-expression to the left of the . operator."
and
"Similarly during name lookup, when an unqualified-id (5.1) used in
the definition of a member function for class X resolves to a static
member, an enumerator or a nested type of class X or of a base class
of X, the unqualified-id is transformed into a qualified-id (5.1) in
which the nested-name-specifier names the class of the member
function."
shall be applied to the following code?
#include <iostream>
struct B
{
virtual void f(int)
{ std::cout << "B::f(int)" << std::endl; }
static void f(double)
{ std::cout << "B::f(double)" << std::endl; }
void g()
{
f(0); // calls non-static virtual member function
f(0.); // calls static member function
}
};
struct D : B
{
virtual void f(int)
{ std::cout << "D::f(int)" << std::endl; }
};
int main()
{
D().g();
}
It seems, both transformations shall be applied before the overload
resolution takes place, so, in both calls "f" shall be transformed
into "this->B::f", and the output must be:
B::f(int)
B::f(double)
instead of
D::f(int)
B::f(double)
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: "Johannes Schaub (litb)" <schaub-johannes@web.de>
Date: Sun, 7 Feb 2010 18:43:52 CST Raw View
Nikolay Ivchenkov wrote:
> The last example has another interesting side. Can anybody explain how
> the wordings in N3000 - 9.3.1/3
>
> "When an id-expression (5.1) that is not part of a class member access
> syntax (5.2.5) and not used to form a pointer to member (5.3.1) is
> used in the body of a non-static member function of class X, if name
> lookup (3.4.1) resolves the name in the id-expression to a non-static
> non-type member of some class C, the id-expression is transformed into
> a class member access expression (5.2.5) using (*this) (9.3.2) as the
> postfix-expression to the left of the . operator."
>
> and
>
> "Similarly during name lookup, when an unqualified-id (5.1) used in
> the definition of a member function for class X resolves to a static
> member, an enumerator or a nested type of class X or of a base class
> of X, the unqualified-id is transformed into a qualified-id (5.1) in
> which the nested-name-specifier names the class of the member
> function."
>
> shall be applied to the following code?
>
> #include <iostream>
>
> struct B
> {
> virtual void f(int)
> { std::cout << "B::f(int)" << std::endl; }
> static void f(double)
> { std::cout << "B::f(double)" << std::endl; }
> void g()
> {
> f(0); // calls non-static virtual member function
> f(0.); // calls static member function
> }
> };
>
> struct D : B
> {
> virtual void f(int)
> { std::cout << "D::f(int)" << std::endl; }
> };
>
> int main()
> {
> D().g();
> }
>
> It seems, both transformations shall be applied before the overload
> resolution takes place, so, in both calls "f" shall be transformed
> into "this->B::f", and the output must be:
>
> B::f(int)
> B::f(double)
>
> instead of
>
> D::f(int)
> B::f(double)
>
Interesting. It doesn't seem clear to me either, but your interpretation
makes sense to me. And the text looks to me likewise as if it would apply
before overload resolution. One odd thing tho: If the above applies before
overload resolution, then 13.3.1.1.1/3 does not need to bother with
unqualified function calls where "this" is in scope anymore, i think.
It certainly happens before access checking, though (see 11.2/6).
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Mon, 11 Jan 2010 18:16:51 CST Raw View
Consider N3000 - 9.3.1/3:
"When an id-expression (5.1) that is not part of a class member access
syntax (5.2.5) and not used to form a pointer to member (5.3.1) is
used in the body of a non-static member function of class X, if name
lookup (3.4.1) resolves the name in the id-expression to a non-static
non-type member of some class C, the id-expression is transformed into
a class member access expression (5.2.5) using (*this) (9.3.2) as the
postfix-expression to the left of the . operator. [ Note: if C is not
X or a base class of X, the class member access expression is ill-
formed. end note ]"
Can someone explain why an implicit class member access is formed even
if C is not X or a base class of X?
struct A
{
int m;
};
struct B
{
int m;
void f()
{
sizeof B::m;
// OK: transformed into "sizeof (*this).B::m"
sizeof A::m;
// Error: transformed into "sizeof (*this).A::m"
// What is the reason for that?
}
};
int main()
{
sizeof A::m; // OK
}
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: "Johannes Schaub (litb)" <schaub-johannes@web.de>
Date: Tue, 12 Jan 2010 03:44:22 CST Raw View
Nikolay Ivchenkov wrote:
> Consider N3000 - 9.3.1/3:
>
> "When an id-expression (5.1) that is not part of a class member access
> syntax (5.2.5) and not used to form a pointer to member (5.3.1) is
> used in the body of a non-static member function of class X, if name
> lookup (3.4.1) resolves the name in the id-expression to a non-static
> non-type member of some class C, the id-expression is transformed into
> a class member access expression (5.2.5) using (*this) (9.3.2) as the
> postfix-expression to the left of the . operator. [ Note: if C is not
> X or a base class of X, the class member access expression is ill-
> formed. end note ]"
>
> Can someone explain why an implicit class member access is formed even
> if C is not X or a base class of X?
>
> struct A
> {
> int m;
> };
>
> struct B
> {
> int m;
> void f()
> {
> sizeof B::m;
> // OK: transformed into "sizeof (*this).B::m"
>
> sizeof A::m;
> // Error: transformed into "sizeof (*this).A::m"
> // What is the reason for that?
> }
> };
>
> int main()
> {
> sizeof A::m; // OK
> }
>
>
I sent a defect repoort about the error case to WMM some time ago. I think
one should only check whether it names a base member when not in an
unevaluated operand, or not even transform it to that. Transforming to class
member access always was done with http://www.open-
std.org/jtc1/sc22/wg21/docs/cwg_defects.html#515
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Tue, 12 Jan 2010 14:51:38 CST Raw View
On 12 Jan, 12:44, "Johannes Schaub (litb)" <schaub-johan...@web.de>
wrote:
> I think
> one should only check whether it names a base member when not in an
> unevaluated operand, or not even transform it to that. Transforming to class
> member access always was done withhttp://www.open-
> std.org/jtc1/sc22/wg21/docs/cwg_defects.html#515
OK, lets look at another example:
struct A
{
void foo(double) {}
static void foo(int) {}
};
template <typename T>
struct B : A {};
template <>
struct B<void> {};
template <typename T>
struct C : B<T>
{
void f()
{
A::foo(0); // see comments below
}
};
int main()
{
A::foo(0);
// OK: overload resolution selects the static member function
C<int>().f();
// OK: "(*this).A::foo" is correct within the body of C<int>::f
C<void>().f();
// ill-formed?
// is "A::foo" transformed into "(*this).A::foo"?
}
Here the name lookup finds non-static member function and static
member function. N3000 - 9.3.1/3 says nothing about overload
resolution. So, what really happens? If within the body of f "A::foo"
is always transformed into "(*this).A::foo", then the program is ill-
formed. Moreover, according to 13.3.1.1.1/3, the implied object
argument would be a contrived object of type A, but the part "or
refers to another class" of the wording
"If the keyword this is not in scope or refers to another class, then
a contrived object of type T becomes the implied object argument"
becomes irrelevant.
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: "Johannes Schaub (litb)" <schaub-johannes@web.de>
Date: Tue, 12 Jan 2010 16:53:12 CST Raw View
Nikolay Ivchenkov wrote:
> On 12 Jan, 12:44, "Johannes Schaub (litb)" <schaub-johan...@web.de>
> wrote:
>
>> I think
>> one should only check whether it names a base member when not in an
>> unevaluated operand, or not even transform it to that. Transforming to
>> class member access always was done withhttp://www.open-
>> std.org/jtc1/sc22/wg21/docs/cwg_defects.html#515
>
> OK, lets look at another example:
>
> struct A
> {
> void foo(double) {}
> static void foo(int) {}
> };
>
> template <typename T>
> struct B : A {};
> template <>
> struct B<void> {};
>
> template <typename T>
> struct C : B<T>
> {
> void f()
> {
> A::foo(0); // see comments below
> }
> };
>
> int main()
> {
> A::foo(0);
> // OK: overload resolution selects the static member function
>
> C<int>().f();
> // OK: "(*this).A::foo" is correct within the body of C<int>::f
>
> C<void>().f();
> // ill-formed?
> // is "A::foo" transformed into "(*this).A::foo"?
> }
>
> Here the name lookup finds non-static member function and static
> member function. N3000 - 9.3.1/3 says nothing about overload
> resolution. So, what really happens? If within the body of f "A::foo"
> is always transformed into "(*this).A::foo", then the program is ill-
> formed. Moreover, according to 13.3.1.1.1/3, the implied object
> argument would be a contrived object of type A, but the part "or
> refers to another class" of the wording
>
> "If the keyword this is not in scope or refers to another class, then
> a contrived object of type T becomes the implied object argument"
>
> becomes irrelevant.
>
Nice testcase, i think. Agreed, this 13.3.1.1.1 looks weird given the class
member access would be ill formed anyway. I'm not understanding why they did
that change to always transform to class member access in that DR. It
sounded like only a note was needed to clearify the matters.
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]