Consider the following snippet:
struct X { static bool called; };
struct Y : X
{
Y() { called = true; } // g++ is happy with this
};
template <int N>
struct XT { static bool called; };
template <int N> bool XT<N>::called;
template <int N>
struct YT : XT<N>
{
YT() { called = true; }/ / g++ is unhappy with this
};
int main()
{
YT<0> yt;
}
g++ is unhappy with the assignment to called in YT's constructor:
/tmp/x.cc: In constructor 'YT<N>::YT()':
/tmp/x.cc:16: error: 'called' was not declared in this scope
But it's happy with the non-template version.
Is this a compiler issue, or have I missed something in the standard?
--
Ian Collins.
|
|
0
|
|
|
|
Reply
|
ian-news (9880)
|
7/14/2008 8:44:16 AM |
|
On Jul 14, 10:44 am, Ian Collins <ian-n...@hotmail.com> wrote:
> Consider the following snippet:
> struct X { static bool called; };
> struct Y : X
> {
> Y() { called =3D true; } // g++ is happy with this
> };
> template <int N>
> struct XT { static bool called; };
> template <int N> bool XT<N>::called;
> template <int N>
> struct YT : XT<N>
> {
> YT() { called =3D true; }/ / g++ is unhappy with this
Normal. The expression is not dependent, so the compiler does
name lookup exclusively at the point of definition. At which
time, it hasn't the slightest idea what might be in XT<N> (since
it is a dependent base). See =A714.6.2/3: "In the definition of a
class template or 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
either at the point of definition of the class template or
member or during an instantiation of the class template or
member." (Since called is not dependent here, the only lookup
is at the point of definition.)
You have to write either "this->called =3D true", or
"XT<N>::called =3D true".
> };
> int main()
> {
> YT<0> yt;
> }
> g++ is unhappy with the assignment to called in YT's constructor:
> /tmp/x.cc: In constructor 'YT<N>::YT()':
> /tmp/x.cc:16: error: 'called' was not declared in this scope
> But it's happy with the non-template version.
> Is this a compiler issue, or have I missed something in the standard?
The fact that a dependent base class does not participate in
non-dependent name lookup.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34
|
|
0
|
|
|
|
Reply
|
james.kanze (9594)
|
7/14/2008 10:41:12 AM
|
|
James Kanze wrote:
>
>> Is this a compiler issue, or have I missed something in the standard?
>
> The fact that a dependent base class does not participate in
> non-dependent name lookup.
>
Thanks! The code was originally built with Sun CC, which is a little
lax in that area. Mind you, in this case, it's pretty obvious where the
name originates.
--
Ian Collins.
|
|
0
|
|
|
|
Reply
|
ian-news (9880)
|
7/14/2008 10:55:57 AM
|
|
On Jul 14, 12:55 pm, Ian Collins <ian-n...@hotmail.com> wrote:
> James Kanze wrote:
> >> Is this a compiler issue, or have I missed something in the standard?
> > The fact that a dependent base class does not participate in
> > non-dependent name lookup.
> Thanks! The code was originally built with Sun CC, which is a
> little lax in that area. Mind you, in this case, it's pretty
> obvious where the name originates.
It it. Suppose there's a specialization of the base class for
the type, which doesn't have it? The compiler can't assume that
the template definition which it's already seen corresponds to
the instantiation it will get.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34
|
|
0
|
|
|
|
Reply
|
james.kanze (9594)
|
7/14/2008 3:21:59 PM
|
|
James Kanze wrote:
> On Jul 14, 12:55 pm, Ian Collins <ian-n...@hotmail.com> wrote:
>> James Kanze wrote:
>
>>>> Is this a compiler issue, or have I missed something in the standard?
>
>>> The fact that a dependent base class does not participate in
>>> non-dependent name lookup.
>
>> Thanks! The code was originally built with Sun CC, which is a
>> little lax in that area. Mind you, in this case, it's pretty
>> obvious where the name originates.
>
> It it. Suppose there's a specialization of the base class for
> the type, which doesn't have it? The compiler can't assume that
> the template definition which it's already seen corresponds to
> the instantiation it will get.
>
But it must know which base class is used (specialised or not) at the
point of instantiation. For example:
template <int N>
struct X { static bool called; };
template <int N> bool X<N>::called;
template <int N> struct Y : X<N>
{
Y() { called = true; }
};
template<> struct X<0> {};
int main()
{
Y<0> y;
}
Will fail to compile.
--
Ian Collins.
|
|
0
|
|
|
|
Reply
|
ian-news (9880)
|
7/16/2008 3:29:22 AM
|
|
On Jul 16, 5:29 am, Ian Collins <ian-n...@hotmail.com> wrote:
> James Kanze wrote:
> > On Jul 14, 12:55 pm, Ian Collins <ian-n...@hotmail.com> wrote:
> >> James Kanze wrote:
> >>>> Is this a compiler issue, or have I missed something in
> >>>> the standard?
> >>> The fact that a dependent base class does not participate in
> >>> non-dependent name lookup.
> >> Thanks! The code was originally built with Sun CC, which is a
> >> little lax in that area. Mind you, in this case, it's pretty
> >> obvious where the name originates.
> > It it. Suppose there's a specialization of the base class for
> > the type, which doesn't have it? The compiler can't assume that
> > the template definition which it's already seen corresponds to
> > the instantiation it will get.
> But it must know which base class is used (specialised or not)
> at the point of instantiation.
At the point of instantiation. Non-dependent name lookup occurs
at the point of definition, and only at the point of definition.
If you make the name dependent in some way (e.g. "X<N>::called",
or "this->called") name lookup is deferred to the point of
instantiation, and the name in the base class is found.
> For example:
> template <int N>
> struct X { static bool called; };
> template <int N> bool X<N>::called;
> template <int N> struct Y : X<N>
> {
> Y() { called =3D true; }
> };
> template<> struct X<0> {};
> int main()
> {
> Y<0> y;
> }
> Will fail to compile.
Yes. And it will fail to compile even if you make the name
dependent.
Unless things have changed in the very latest versions, Sun CC
does not yet (fully) implement two phase name look up. The
"classical" lookup (used by most compilers before the standard)
was only at the point of instantiation---in many ways, a
template was like a macro, with the compiler treating it as just
a sequence of tokens until instantiation. The standard
introducted two phase lookup (very early in the standardization
process, so the implementors really knew what was coming---they
just chose to ignore it) in order to solve two problems: it
allows significantly more error checking at the point of
definition (but requires typename and template in return), and
it prevents "name hijacking", sort of. (IMHO, the cure is worse
than the disease: in my experience, name hijacking was never a
real problem anyway, and the standard solution doesn't really
solve it either. And of course, I would never deliver a
template without having tested it thoroughly, much less without
having instantiated it. Any errors that the compiler can catch
at the definition point wouldn't have gotten through my unit
tests, so it doesn't really matter.)
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34
|
|
0
|
|
|
|
Reply
|
james.kanze (9594)
|
7/16/2008 9:08:22 AM
|
|
James Kanze wrote:
> On Jul 16, 5:29 am, Ian Collins <ian-n...@hotmail.com> wrote:
>> James Kanze wrote:
>>> On Jul 14, 12:55 pm, Ian Collins <ian-n...@hotmail.com> wrote:
>>>> James Kanze wrote:
>
>>>>>> Is this a compiler issue, or have I missed something in
>>>>>> the standard?
>
>>>>> The fact that a dependent base class does not participate in
>>>>> non-dependent name lookup.
>
>>>> Thanks! The code was originally built with Sun CC, which is a
>>>> little lax in that area. Mind you, in this case, it's pretty
>>>> obvious where the name originates.
>
>>> It it. Suppose there's a specialization of the base class for
>>> the type, which doesn't have it? The compiler can't assume that
>>> the template definition which it's already seen corresponds to
>>> the instantiation it will get.
>
>> But it must know which base class is used (specialised or not)
>> at the point of instantiation.
>
> At the point of instantiation. Non-dependent name lookup occurs
> at the point of definition, and only at the point of definition.
> If you make the name dependent in some way (e.g. "X<N>::called",
> or "this->called") name lookup is deferred to the point of
> instantiation, and the name in the base class is found.
>
True, but I've never really seen the benefit of that change.
<sip>
>
>> Will fail to compile.
>
> Yes. And it will fail to compile even if you make the name
> dependent.
>
> Unless things have changed in the very latest versions, Sun CC
> does not yet (fully) implement two phase name look up. The
> "classical" lookup (used by most compilers before the standard)
> was only at the point of instantiation---in many ways, a
> template was like a macro, with the compiler treating it as just
> a sequence of tokens until instantiation. The standard
> introducted two phase lookup (very early in the standardization
> process, so the implementors really knew what was coming---they
> just chose to ignore it) in order to solve two problems: it
> allows significantly more error checking at the point of
> definition (but requires typename and template in return), and
> it prevents "name hijacking", sort of.
So that's the reason, I never could see why. I hope CC keeps on with
the old way, I bet there's a lot of code on Solaris that relies on it.
That includes a lot of mine!
Two phase lookup just leads to a lot of unnecessarily verbose and
cluttered code for no real gain.
> (IMHO, the cure is worse
> than the disease: in my experience, name hijacking was never a
> real problem anyway, and the standard solution doesn't really
> solve it either. And of course, I would never deliver a
> template without having tested it thoroughly, much less without
> having instantiated it. Any errors that the compiler can catch
> at the definition point wouldn't have gotten through my unit
> tests, so it doesn't really matter.)
>
Ah, so we agree.
--
Ian Collins.
|
|
0
|
|
|
|
Reply
|
ian-news (9880)
|
7/16/2008 10:02:44 AM
|
|
On Jul 16, 12:02 pm, Ian Collins <ian-n...@hotmail.com> wrote:
> James Kanze wrote:
[...]
> > At the point of instantiation. Non-dependent name lookup occurs
> > at the point of definition, and only at the point of definition.
> > If you make the name dependent in some way (e.g. "X<N>::called",
> > or "this->called") name lookup is deferred to the point of
> > instantiation, and the name in the base class is found.
> True, but I've never really seen the benefit of that change.
I wouldn't say that there is no benefit, but...
> So that's the reason, I never could see why. I hope CC keeps
> on with the old way, I bet there's a lot of code on Solaris
> that relies on it. That includes a lot of mine!
> Two phase lookup just leads to a lot of unnecessarily verbose
> and cluttered code for no real gain.
IMHO, the real problem is that it isn't immediately clear what
is dependent, and what isn't. And you need subtle tricks (like
putting "this->" in front of the access to a static member) to
force dependency. Had you been required to declare dependency
explicitly, I could accept it.
> > (IMHO, the cure is worse than the disease: in my experience,
> > name hijacking was never a real problem anyway, and the
> > standard solution doesn't really solve it either. And of
> > course, I would never deliver a template without having
> > tested it thoroughly, much less without having instantiated
> > it. Any errors that the compiler can catch at the
> > definition point wouldn't have gotten through my unit tests,
> > so it doesn't really matter.)
> Ah, so we agree.
More or less. IMHO, it's a steep price we pay for relatively
little benefit.
To be fair to the committee, when they first raised the idea,
and made it clear that some form of two phased lookup would be
adopted, there were very, very few implementations of templates
around, so they sort of had to guess what the problems might be.
And it's not really their fault if, having made it clear that
the final standard would have two phased lookup, all of the
implementors plunged in and implemented templates without it, so
we'd have the portability problem. (At the time two phased
lookup was proposed, I think CFront was the only compiler with
templates. Which meant Sun CC, of course, so we'd still have
the cost of upgrading. But why organizations like Microsoft or
g++ introduced templates in a way that ensured that they'd have
to later break code, I don't know.)
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34
|
|
0
|
|
|
|
Reply
|
james.kanze (9594)
|
7/16/2008 5:14:06 PM
|
|
|
7 Replies
58 Views
(page loaded in 0.117 seconds)
|