Topic: template type dependent name lookup


Author: news@ajrh.net (Anthony Heading)
Date: Sat, 24 Mar 2007 21:32:25 GMT
Raw View
This example below compiles cleanly on gcc 4.1.1
with g++ -Wall -ansi -pedantic-errors, and with
MSVC2005 cl -W4, but not with icc -strict_ansi

     template<int N> struct X
     {
         struct I {};
         static void x(I) { }
     };

     template <int N> struct Y :
         public X<N>
     {
         typedef typename X<N>::I I;
         void y() {
             x(I());
         }
     };

     template struct Y<0>;

With the EDG front end, e.g. intel compiler or Comeau

~% icc -strict_ansi -c x.cpp
x.cpp(12): error: identifier "x" is undefined
     x(I());
     ^
     detected during instantiation of "void Y<N>::y() [with N=0]"


Is EDG wrong to complain here?  The I() argument is surely a
template type dependent expression as per 14.6.2.2, and thus
from 14.6.2 the name "x" should also be looked up in the context
at the point of instantiation, which I would expect to lead to
finding the inherited definition.

More authorative views than mine very welcome...

Anthony

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: James Dennett <jdennett@acm.org>
Date: Sat, 24 Mar 2007 21:29:00 CST
Raw View
Anthony Heading wrote:
> This example below compiles cleanly on gcc 4.1.1
> with g++ -Wall -ansi -pedantic-errors, and with
> MSVC2005 cl -W4, but not with icc -strict_ansi
>
>     template<int N> struct X
>     {
>         struct I {};
>         static void x(I) { }
>     };
>
>     template <int N> struct Y :
>         public X<N>
>     {
>         typedef typename X<N>::I I;
>         void y() {
>             x(I());
>         }
>     };
>
>     template struct Y<0>;
>
> With the EDG front end, e.g. intel compiler or Comeau
>
> ~% icc -strict_ansi -c x.cpp
> x.cpp(12): error: identifier "x" is undefined
>     x(I());
>     ^
>     detected during instantiation of "void Y<N>::y() [with N=0]"
>
>
> Is EDG wrong to complain here?  The I() argument is surely a
> template type dependent expression as per 14.6.2.2, and thus
> from 14.6.2 the name "x" should also be looked up in the context
> at the point of instantiation, which I would expect to lead to
> finding the inherited definition.

Phase 1 name lookup won't find an x; the base class
is unknown during parsing of the template.  The lookup
in phase 2, so far as I know, is ADL only, and hence
won't go looking in base classes.  The fix for the
code above would be to write this->x(I()) (even though
x is a static), or to write X<N>::x(I()) explicitly.
This does mean, for example, that all instances of the
class template Y above will be consistent in whether
x is found as a member function or not.

-- James

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: hyrosen@mail.com (Hyman Rosen)
Date: Sun, 25 Mar 2007 08:11:44 GMT
Raw View
Anthony Heading wrote:
>     template<int N> struct X { struct I {}; static void x(I) { } };
>     template <int N> struct Y : public X<N> {
>         typedef typename X<N>::I I;
>         void y() { x(I()); }
>     };
>     template struct Y<0>;
>
> x.cpp(12): error: identifier "x" is undefined
>     detected during instantiation of "void Y<N>::y() [with N=0]"

This is because of 14.6.2/3:
     "In the definition of ... a member of a class template, if a base class
      of the class template depends on a template-parameter, the base class
      scope is not examined during unqualified name lookup ... during an
      instantiation of the ... member."

If you need this to work, just add 'using X<N>::x;' to Y's definition.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "=?iso-8859-1?q?Daniel_Kr=FCgler?=" <daniel.kruegler@googlemail.com>
Date: Sun, 25 Mar 2007 09:59:47 CST
Raw View
Hyman Rosen schrieb:

> Anthony Heading wrote:
> >     template<int N> struct X { struct I {}; static void x(I) { } };
> >     template <int N> struct Y : public X<N> {
> >         typedef typename X<N>::I I;
> >         void y() { x(I()); }
> >     };
> >     template struct Y<0>;
> >
> > x.cpp(12): error: identifier "x" is undefined
> >     detected during instantiation of "void Y<N>::y() [with N=0]"
>
> This is because of 14.6.2/3:
>      "In the definition of ... a member of a class template, if a base class
>       of the class template depends on a template-parameter, the base class
>       scope is not examined during unqualified name lookup ... during an
>       instantiation of the ... member."
>

Hmmh, I wonder why this rule should be superior to
those of argument-dependent look-up described in 3.4.2?
Unfortunately it's not clear whether 14.6.2/3 should be
applied to ADL cases also (we have a lot of active issues
related to ADL).

Interestingly (due to a misunderstanding on my side?) I
would have applied 3.4.2/2, 2nd bullet from 14882:2003:

"If T is a class type [..], its associated classes are:
the class itself; the class of which it is a member, if any;
and its direct and indirect base classes. Its associated
namespaces are the namespaces in which its associated
classes are defined."

My reasoning would be so: During the first phase nothing
is found for x (because it would not look into X<N>), but
during the second phase at the POI it would recognize
that I belongs to the (now known!) Y base class X<0> and
thus x should be correctly found.

Do we have clarification needed here? According to
my understanding both reasonings could be applied and
result in two different results.

I further found that the current writing has changed in a
significant way (N2134): It removed the earlier existing
last bullet of 3.4.2/2 (which used the notion of template-id,
that would not apply for I) and changed the above
quoted 2nd bullet to

"If T is a class type [..], its associated classes are:
the class itself; the class of which it is a member, if any;
and its direct and indirect base classes. Its associated
namespaces are the namespaces in of which its associated
classes are defined members.
Furthermore, if T is a class template specialization, its
associated namespaces and classes also include: the
namespaces and classes associated with the types of
the template arguments provided for template type
parameters (excluding template template parameters);
the namespaces of which any template template arguments
are members; and the classes of which any member
templates used as template template arguments are
members. [ Note: Non-type template arguments do not
contribute to the set of associated namespaces. -end
note ]"

IMO the new wordings even strengthens my above
described argumentation, doesn't it?

Greetings from Bremen,

Daniel

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: richard_corden@hotmail.com (Richard Corden)
Date: Mon, 26 Mar 2007 14:15:10 GMT
Raw View

Daniel Kr=FCgler wrote:
> Hyman Rosen schrieb:
>=20
>> Anthony Heading wrote:
>>>     template<int N> struct X { struct I {}; static void x(I) { } };
>>>     template <int N> struct Y : public X<N> {
>>>         typedef typename X<N>::I I;
>>>         void y() { x(I()); }
>>>     };
>>>     template struct Y<0>;
>>>
>>> x.cpp(12): error: identifier "x" is undefined
>>>     detected during instantiation of "void Y<N>::y() [with N=3D0]"
>> This is because of 14.6.2/3:
>>      "In the definition of ... a member of a class template, if a base=
 class
>>       of the class template depends on a template-parameter, the base =
class
>>       scope is not examined during unqualified name lookup ... during =
an
>>       instantiation of the ... member."
>>
>=20
> Hmmh, I wonder why this rule should be superior to
> those of argument-dependent look-up described in 3.4.2?
> Unfortunately it's not clear whether 14.6.2/3 should be
> applied to ADL cases also (we have a lot of active issues
> related to ADL).
>=20
> Interestingly (due to a misunderstanding on my side?) I
> would have applied 3.4.2/2, 2nd bullet from 14882:2003:
>=20
> "If T is a class type [..], its associated classes are:
> the class itself; the class of which it is a member, if any;
> and its direct and indirect base classes. Its associated
> namespaces are the namespaces in which its associated
> classes are defined."
>=20
> My reasoning would be so: During the first phase nothing
> is found for x (because it would not look into X<N>), but
> during the second phase at the POI it would recognize
> that I belongs to the (now known!) Y base class X<0> and
> thus x should be correctly found.
>=20
> Do we have clarification needed here? According to
> my understanding both reasonings could be applied and
> result in two different results.

ADL finds 'namespace' members.

It is true that the 1st lookup phase will see the dependent argument and=20
perform the additional ADL for 'x' once it's argument types are known.=20
However, that lookup will not consider the static member.


Regards,

Richard



>=20
> I further found that the current writing has changed in a
> significant way (N2134): It removed the earlier existing
> last bullet of 3.4.2/2 (which used the notion of template-id,
> that would not apply for I) and changed the above
> quoted 2nd bullet to
>=20
> "If T is a class type [..], its associated classes are:
> the class itself; the class of which it is a member, if any;
> and its direct and indirect base classes. Its associated
> namespaces are the namespaces in of which its associated
> classes are defined members.
> Furthermore, if T is a class template specialization, its
> associated namespaces and classes also include: the
> namespaces and classes associated with the types of
> the template arguments provided for template type
> parameters (excluding template template parameters);
> the namespaces of which any template template arguments
> are members; and the classes of which any member
> templates used as template template arguments are
> members. [ Note: Non-type template arguments do not
> contribute to the set of associated namespaces. -end
> note ]"
>=20
> IMO the new wordings even strengthens my above
> described argumentation, doesn't it?
>=20
> Greetings from Bremen,
>=20
> Daniel
>=20
> ---
> [ comp.std.c++ is moderated.  To submit articles, try just posting with=
 ]
> [ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu   =
 ]
> [              --- Please see the FAQ before posting. ---              =
 ]
> [ FAQ: http://www.comeaucomputing.com/csc/faq.html                     =
 ]
>=20


--=20
Richard Corden

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: richard_corden@hotmail.com (Richard Corden)
Date: Mon, 26 Mar 2007 17:47:25 GMT
Raw View

Daniel Kr=FCgler wrote:
> Hyman Rosen schrieb:
>=20
>> Anthony Heading wrote:
>>>     template<int N> struct X { struct I {}; static void x(I) { } };
>>>     template <int N> struct Y : public X<N> {
>>>         typedef typename X<N>::I I;
>>>         void y() { x(I()); }
>>>     };
>>>     template struct Y<0>;
>>>
>>> x.cpp(12): error: identifier "x" is undefined
>>>     detected during instantiation of "void Y<N>::y() [with N=3D0]"
>> This is because of 14.6.2/3:
>>      "In the definition of ... a member of a class template, if a base=
 class
>>       of the class template depends on a template-parameter, the base =
class
>>       scope is not examined during unqualified name lookup ... during =
an
>>       instantiation of the ... member."
>>
>=20
> Hmmh, I wonder why this rule should be superior to
> those of argument-dependent look-up described in 3.4.2?
> Unfortunately it's not clear whether 14.6.2/3 should be
> applied to ADL cases also (we have a lot of active issues
> related to ADL).
>=20
> Interestingly (due to a misunderstanding on my side?) I
> would have applied 3.4.2/2, 2nd bullet from 14882:2003:
>=20
> "If T is a class type [..], its associated classes are:
> the class itself; the class of which it is a member, if any;
> and its direct and indirect base classes. Its associated
> namespaces are the namespaces in which its associated
> classes are defined."
>=20

[...]

ADL finds 'namespace' members.

It is true that the 1st lookup phase will see the dependent argument and
perform the additional ADL for 'x' once it's argument types are known.
However, that lookup will not consider the static member.


Regards,

Richard



--=20
Richard Corden

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "=?iso-8859-1?q?Daniel_Kr=FCgler?=" <daniel.kruegler@googlemail.com>
Date: Mon, 26 Mar 2007 13:21:43 CST
Raw View
Richard Corden schrieb:

> ADL finds 'namespace' members.
>
> It is true that the 1st lookup phase will see the dependent argument and
> perform the additional ADL for 'x' once it's argument types are known.
> However, that lookup will not consider the static member.

Ooops, you are totally right! My misunderstanding was that
I translated the notion of associated classes as "generalized"
namespaces (in the sense of class-or-namespace) which have
to be taken into account during ADL. Another reason for that
misunderstanding was related to the wording in 3.4.2/3 (N2134)

"If the ordinary unqualified lookup of the name finds the declaration
of a class member function, or a block-scope function declaration
that is not a using-declaration, the associated namespaces are
not considered."

which does *not* say, that the member function (or block-scope
function declaration) is not taken into the set - this seems to be
implied.

To bring that all into one point: Associated classes are *not* the
places to search for the functions, they are only the "traces" to
determine their corresponding namespaces where the (free)
functions have to be found, right?

Personally I think that the example in 14.6.2/3 should be
extended to use also an dependent name in the derived class.

Thanks for your clarification,

Daniel

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]