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

qualified function names and two phase lookup

14 views
Skip to first unread message

Balog Pal

unread,
May 20, 2003, 12:08:42 PM5/20/03
to
Herb just runs GOTW on two phase lookup rules.

template<typename T>
class X : public Y<T> { // 1 ?
E f( int ) { // 2 ?
g(); // 3 ?
this->h(); // 4 ?

T t1, t2;
cout << t1; // 5 ?
swap( t1, t2 ); // 6 ?
std::swap( t1, t2 ); // 7 ?
}
};

The answers I've seen so far show lines 6 and 7 are different.

> See 14.6.2p1:
>
> "In an expression of the form:
>
> postfix-expression ( expression-list opt )
>
> where the postfix-expression is an identifier, the identifier denotes a
> dependent name if and only if any of the expressions in the
> expression-list is
> a type-dependent expression (14.6.2.2)."
>
> The key is that a qualified name is not an identifier, so this doesn't
> apply.

My question here is whether that was intended bahavior, or an overlook.
In the first case what is the rationale? I find this difference just
horrifying.

Intuitively I'd think qualification would remove ADL, and narrow the search
scope but _leave the lookup to the second phase_. Where the vital
information is present.

I put general purpose templates (stuff like swap) in a common file, that is
included early in every file.
Actual types are defined much later, functions using them even later. How
am I supposed to use namespaces to deal with this thing?

If that was not intended, is there a DR or some resolution expected anytime
soon?


Also, I'd look for the relevant part for std::swap as follows:
14.6.2p1 does not apply. (not matching the form)
14.6.2.2p1 does apply so it will be dependent unless exception found
14.6.2.2p2 does apply. the 'only if' secton at tail does not match. The
front bullets do not define exceptiontions.

So here I'd rule the expressions dependent. Then apply 14.6.4. Why's that
bad reasoning?


Paul


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

Gabriel Dos Reis

unread,
May 20, 2003, 3:29:34 PM5/20/03
to
pa...@lib.hu ("Balog Pal") writes:

| Herb just runs GOTW on two phase lookup rules.
|
| template<typename T>
| class X : public Y<T> { // 1 ?
| E f( int ) { // 2 ?
| g(); // 3 ?
| this->h(); // 4 ?
|
| T t1, t2;
| cout << t1; // 5 ?
| swap( t1, t2 ); // 6 ?
| std::swap( t1, t2 ); // 7 ?
| }
| };
|
| The answers I've seen so far show lines 6 and 7 are different.
|
| > See 14.6.2p1:
| >
| > "In an expression of the form:
| >
| > postfix-expression ( expression-list opt )
| >
| > where the postfix-expression is an identifier, the identifier denotes a
| > dependent name if and only if any of the expressions in the
| > expression-list is
| > a type-dependent expression (14.6.2.2)."
| >
| > The key is that a qualified name is not an identifier, so this doesn't
| > apply.
|
| My question here is whether that was intended bahavior, or an overlook.

>From various discussions I've seen on committee reflectors, that
always appeared to me as an intended behaviour.

| In the first case what is the rationale? I find this difference just
| horrifying.

What is horrifying about it? Please be specific.

| Intuitively I'd think qualification would remove ADL, and narrow the search
| scope but _leave the lookup to the second phase_. Where the vital
| information is present.

Which vital information? Clearly std::swap is an id-expression that
is NOT type-dependent, so from general rules, it makes sense it be
bound at the point of definition.

| I put general purpose templates (stuff like swap) in a common file, that is
| included early in every file.
| Actual types are defined much later, functions using them even later. How
| am I supposed to use namespaces to deal with this thing?

sounds like you want ADL :-)

| If that was not intended, is there a DR or some resolution expected anytime
| soon?
|
|
| Also, I'd look for the relevant part for std::swap as follows:
| 14.6.2p1 does not apply. (not matching the form)

right.

| 14.6.2.2p1 does apply so it will be dependent unless exception found
| 14.6.2.2p2 does apply. the 'only if' secton at tail does not match. The

how?

| front bullets do not define exceptiontions.
|
| So here I'd rule the expressions dependent. Then apply 14.6.4. Why's that
| bad reasoning?

Because you missed 14.6.2.2/3

An id-expression is type-dependent if it contains:
-- an identifier that was declared with a dependent type,
-- a template-id that is dependent,
-- a conversion-function-id that specifies a dependent type,
-- a nested-name-specifier that contains a class-name that names a
dependent type.

--
Gabriel Dos Reis, g...@integrable-solutions.net

Balog Pal

unread,
May 20, 2003, 8:08:11 PM5/20/03
to
"Gabriel Dos Reis" <g...@integrable-solutions.net> wrote in message
news:m3y911i...@uniton.integrable-solutions.net...

> What is horrifying about it? Please be specific.

Well. When I write foo(T) I want it to find some foo relevant to T at the
use point.
If I want to be more specific I say N::foo(T), and that will limit _where_
foo is searched, but nothing else.

Coming to templates the case is similar. I put foo(T), and expect the same.
Ant it will be the same. But if I want to be more specific wrt foo annd use
N::, it will change not only the searching scope, but also the WHEN the
lookup takes place, and moves the POINT to where I don't expect it.
Especially as T is nonexistent at that point.

> | Intuitively I'd think qualification would remove ADL, and narrow the
search
> | scope but _leave the lookup to the second phase_. Where the vital
> | information is present.
>
> Which vital information? Clearly std::swap is an id-expression that
> is NOT type-dependent

Using that logic swap is not tependent either. What the qualification
changes? The arguments make the expression dependent.

>, so from general rules, it makes sense it be
> bound at the point of definition.

I fail to see what is that sense right now. In case of swap I have
specialisations. Those will be defined _after_ this template. And I
expect those used.

And forget std::swap, think N::foo. I have a bunch of overloaded functions
in namespace N. (Possibly also a template.) I want the correct candidate
picked for foo. How that can be found at definition of the general template?

> sounds like you want ADL :-)

No, I want the regular lookup, just at the point of instantiation, not at
definition.

> | 14.6.2.2p1 does apply so it will be dependent unless exception found
> | 14.6.2.2p2 does apply. the 'only if' secton at tail does not match. The
>
> how?

DOH, I mistyped the second, it supposed to be p3 not p2.

> Because you missed 14.6.2.2/3
>
> An id-expression is type-dependent if it contains:
> -- an identifier that was declared with a dependent type,
> -- a template-id that is dependent,
> -- a conversion-function-id that specifies a dependent type,
> -- a nested-name-specifier that contains a class-name that names a
> dependent type.

This part says 'if', not 'if and only if'. So that does not add to
_exceptional_ cases. Just lists some explicit cases of dependent
id-expressions in my intrpretation.

Possibly that's the wrong interpretation.

Paul

Peter Dimov

unread,
May 21, 2003, 1:19:59 PM5/21/03
to
pa...@lib.hu ("Balog Pal") wrote in message news:<3eca...@andromeda.datanet.hu>...

> "Gabriel Dos Reis" <g...@integrable-solutions.net> wrote in message
> news:m3y911i...@uniton.integrable-solutions.net...
>
> > What is horrifying about it? Please be specific.
>
> Well. When I write foo(T) I want it to find some foo relevant to T at the
> use point.
> If I want to be more specific I say N::foo(T), and that will limit _where_
> foo is searched, but nothing else.
>
> Coming to templates the case is similar. I put foo(T), and expect the same.
> Ant it will be the same. But if I want to be more specific wrt foo annd use
> N::, it will change not only the searching scope, but also the WHEN the
> lookup takes place, and moves the POINT to where I don't expect it.
> Especially as T is nonexistent at that point.

It only looks counter-intuitive at first sight. ;-)

When you write foo(x) you enable both normal and argument dependent
lookup. When you qualify the function name - N::foo(x) - you
explicitly specify the namespace, and as a consequence, you inhibit
argument dependent lookup. Looks logical so far, right? Note that by
disabling ADL, you also disabled ADL in N::, but it doesn't matter at
this point.

Moving to templates. Point of definition does both normal and argument
dependent lookup, point of instantiation does ADL only (14.6.4/1.)

When you disable ADL by writing N::foo(x), the only lookup that
remains is normal lookup done at point of definition. Point of
instantiation lookup is implicitly disabled as a consequence of the
interaction between 3.4.2/1 and 14.6.4/1.

James Kanze

unread,
May 21, 2003, 1:21:45 PM5/21/03
to
g...@integrable-solutions.net (Gabriel Dos Reis) wrote in message
news:<m3y911i...@uniton.integrable-solutions.net>...

> | > See 14.6.2p1:

I suspect that it is half and half. I wouldn't be surprised if no one
actually considered the exact case, but it seems to follow from the
general rules.

> | In the first case what is the rationale? I find this difference just
> | horrifying.

> What is horrifying about it? Please be specific.

I'm not sure myself. (Horrifying is perhaps a bit strong, I find two
phase look-up a bit daunting to begin with.)

Just to be sure I understand what is going on, if I write:

void f( int ) { std::cout << "int\n" ; }
void f( long ) { std::cout << "long\n" ; }

template< typename T >
class C {
public:
C::C() { ::f( T() ) ; }
} ;

void f( char ) { std::cout << "char\n" ; }

int
main()
{
C<char> aC ;
return 0 ;
}

The output should be "int", and not "char". In other words, the
overload set is fixed at template definition, although the overload
resolution cannot actually take place until instantiation.

--
James Kanze GABI Software mailto:ka...@gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, Tél. : +33 (0)1 30 23 45 16

Daveed Vandevoorde

unread,
May 21, 2003, 3:27:24 PM5/21/03
to
pa...@lib.hu ("Balog Pal") wrote:
> Herb just runs GOTW on two phase lookup rules.
>
> template<typename T>
> class X : public Y<T> { // 1 ?
> E f( int ) { // 2 ?
> g(); // 3 ?
> this->h(); // 4 ?
>
> T t1, t2;
> cout << t1; // 5 ?
> swap( t1, t2 ); // 6 ?
> std::swap( t1, t2 ); // 7 ?
> }
> };
>
> The answers I've seen so far show lines 6 and 7 are different.

Indeed.

> > See 14.6.2p1:
> >
> > "In an expression of the form:
> >
> > postfix-expression ( expression-list opt )
> >
> > where the postfix-expression is an identifier, the identifier denotes a
> > dependent name if and only if any of the expressions in the
> > expression-list is
> > a type-dependent expression (14.6.2.2)."
> >
> > The key is that a qualified name is not an identifier, so this doesn't
> > apply.
>
> My question here is whether that was intended bahavior, or an overlook.

It was intended.

> In the first case what is the rationale? I find this difference just
> horrifying.
>
> Intuitively I'd think qualification would remove ADL, and narrow the search
> scope but _leave the lookup to the second phase_. Where the vital
> information is present.

Your intuition is correct, but you might be misunderstanding
the unqualified case. In line 6, swap undergoes both OL
(ordinary lookup) and ADL (argument-dependent lookup). The OL
part happens at the point of definition (phase 1), and the ADL
part happens at the POI (point of instantiation; phase 2). If
you remove the ADL part, you're left with a phase 1 lookup only.

So it makes sense that std::swap in line 7 is only looked up
using qualified name lookup in phase 1.

> I put general purpose templates (stuff like swap) in a common file, that is
> included early in every file.
> Actual types are defined much later, functions using them even later. How
> am I supposed to use namespaces to deal with this thing?

Well, if your std::swap is in scope already, there is no
problem. You'll still pick up specializations that appear
later on (because those are not selected by lookup), but
without ADL you won't pick up later std::swap overloads.

> If that was not intended, is there a DR or some resolution expected anytime
> soon?

It was entirely intended.

> Also, I'd look for the relevant part for std::swap as follows:
> 14.6.2p1 does not apply. (not matching the form)
> 14.6.2.2p1 does apply so it will be dependent unless exception found
> 14.6.2.2p2 does apply. the 'only if' secton at tail does not match. The
> front bullets do not define exceptiontions.
>
> So here I'd rule the expressions dependent. Then apply 14.6.4. Why's that
> bad reasoning?

I suspect you're confusing "dependent expression" and
"dependent name." The "name" std::swap is not dependent,
and therefore 14.6.4 does not apply. The expression
"std::swap(t1, t2)" is type-dependent, and hence it could
potentially cause another identifier to be a dependent
name (not an issue here, since it is a complete expression).

Daveed

Gabriel Dos Reis

unread,
May 21, 2003, 3:27:46 PM5/21/03
to
pa...@lib.hu ("Balog Pal") writes:

| "Gabriel Dos Reis" <g...@integrable-solutions.net> wrote in message
| news:m3y911i...@uniton.integrable-solutions.net...
|
| > What is horrifying about it? Please be specific.
|
| Well. When I write foo(T) I want it to find some foo relevant to T at the
| use point.

Not actually. foo(T) means take a foo among those that happen to be visible
at the point of definition of enclosing scope, and possibly those
reachable by looking at the T.

Think about

namespace M
{
void foo(double); // #1
}

namespace N
{
using namespace M;
void g(int i)
{
foo(i); // #2
}
}

namespace M
{
void foo(int); // #3
}

int main()
{
N::g(2);
}

Line #2 calls #1 not #3 even though when N::g is called a better foo
is #3.


| If I want to be more specific I say N::foo(T), and that will limit _where_
| foo is searched, but nothing else.

No. What you wrote is, please take that foo apparently in N, now.

| Coming to templates the case is similar.

Templates are *meta* linguistic constructs with respect to non-template
constructs. Arguments based on analogy are very suspicious.

| I put foo(T), and expect the same.
| Ant it will be the same. But if I want to be more specific wrt foo annd use
| N::, it will change not only the searching scope, but also the WHEN the
| lookup takes place, and moves the POINT to where I don't expect it.

There is nothing new. That already happens in the non-template case.

| Especially as T is nonexistent at that point.

That is immaterial: T is a meta-variable. T does not need to be
present before defining meta-abstractions operating on it.

| > | Intuitively I'd think qualification would remove ADL, and narrow the
| search
| > | scope but _leave the lookup to the second phase_. Where the vital
| > | information is present.
| >
| > Which vital information? Clearly std::swap is an id-expression that
| > is NOT type-dependent
|
| Using that logic swap is not tependent either.

See the appropriate definition of being dependent.

| What the qualification changes?

scoping.

| The arguments make the expression dependent.

Yes but not the qualified-id.

It seems you're using templates where actually what you want is macro
expansion.

| >, so from general rules, it makes sense it be
| > bound at the point of definition.
|
| I fail to see what is that sense right now. In case of swap I have
| specialisations.

If you have *specializations* then you don't need to worry anout
anything. Because name lookup does not find specializations. It
finds primary templates, and specializations are selected by matching
partial specializations

| Those will be defined _after_ this template. And I
| expect those used.

It is a specialization, then it will be found.

| And forget std::swap, think N::foo.

That is immaterial for this particular discussion. But I'll
concentrate on your foo.

| I have a bunch of overloaded functions in namespace N.

Please do make a clear distinction bewteen overloads and
specializations. The two things do not follow the same name lookup rules.

| (Possibly also a template.) I want the correct candidate
| picked for foo. How that can be found at definition of the general template?

Write your template and/or your functions so that they can be found.
That is the general answer I can give to the general question. If you
have specific issue then write it out and I'll try to address it.

| > sounds like you want ADL :-)
|
| No, I want the regular lookup, just at the point of instantiation, not at
| definition.

so actually you want macro substitution. That is a possible template
design, but none that I would like to have. See the recent discussion
on export and whish list point of not intereferring with the meaning
of an instantiation.

the choice was deliberate: early binding when possible.

| > | 14.6.2.2p1 does apply so it will be dependent unless exception found
| > | 14.6.2.2p2 does apply. the 'only if' secton at tail does not match. The
| >
| > how?
|
| DOH, I mistyped the second, it supposed to be p3 not p2.
|
| > Because you missed 14.6.2.2/3
| >
| > An id-expression is type-dependent if it contains:
| > -- an identifier that was declared with a dependent type,
| > -- a template-id that is dependent,
| > -- a conversion-function-id that specifies a dependent type,
| > -- a nested-name-specifier that contains a class-name that names a
| > dependent type.
|
| This part says 'if', not 'if and only if'. So that does not add to
| _exceptional_ cases. Just lists some explicit cases of dependent
| id-expressions in my intrpretation.
|
| Possibly that's the wrong interpretation.

The above is a definition and it does not need to be phrased in terms
of "if and only if". All it says is what it means for an
id-expression to be *type*-dependent. Since none of the bullets here,
nor found in the general definition of "dependent name" says a
qualified-id, the nested-name-specified of which is not dependent,
is dependent you cannot conclude that such a thing is dependent.

--
Gabriel Dos Reis, g...@integrable-solutions.net

---

Terje Slettebø

unread,
May 21, 2003, 3:28:02 PM5/21/03
to
""Balog Pal"" <pa...@lib.hu> wrote in message
news:3eca...@andromeda.datanet.hu...

> "Gabriel Dos Reis" <g...@integrable-solutions.net> wrote in message
> news:m3y911i...@uniton.integrable-solutions.net...
>
> And forget std::swap, think N::foo. I have a bunch of overloaded functions
> in namespace N. (Possibly also a template.) I want the correct candidate
> picked for foo. How that can be found at definition of the general
template?
>
> > sounds like you want ADL :-)
>
> No, I want the regular lookup, just at the point of instantiation, not at
> definition.

It seems that you don't get one, using the current standard. For example the
following fails to compile on Comeau C++:

namespace test
{
}

template<class T>
void A()
{
test::f(T()); // error: namespace "test" has no member "f"
}

namespace test
{
template<class T>
void f(T) {}
}

int main()
{
A<int>();
}


Regards,

Terje

William M. Miller

unread,
May 21, 2003, 3:28:21 PM5/21/03
to
""Balog Pal"" <pa...@lib.hu> wrote in message
news:3eca...@andromeda.datanet.hu...
> "Gabriel Dos Reis" <g...@integrable-solutions.net> wrote in message
> news:m3y911i...@uniton.integrable-solutions.net...
>
> > What is horrifying about it? Please be specific.
>
> Well. When I write foo(T) I want it to find some foo relevant to T at the
> use point.
> If I want to be more specific I say N::foo(T), and that will limit _where_
> foo is searched, but nothing else.
>
> Coming to templates the case is similar. I put foo(T), and expect the
same.
> Ant it will be the same. But if I want to be more specific wrt foo annd
use
> N::, it will change not only the searching scope, but also the WHEN the
> lookup takes place, and moves the POINT to where I don't expect it.
> Especially as T is nonexistent at that point.

Expressions inside templates are different from expressions in
other contexts. Ordinary expressions only have a single point
of context. In a template, you have both the definition context
and the instantiation context. Somehow the contexts have to be
merged. The mechanism you want would involve ordinary (lexical)
lookup from both contexts. (I mean that some names would require
ordinary lookup from the definition context and others from the
instantiation context, not necessarily that the same name would
be looked up in both -- although some would like that feature, as
well.) The Committee decided that that was too difficult and
confusing, so it eliminated the lexical lookup from the
instantiation context. More below.

> > | Intuitively I'd think qualification would remove ADL, and narrow the
> search
> > | scope but _leave the lookup to the second phase_. Where the vital
> > | information is present.
> >
> > Which vital information? Clearly std::swap is an id-expression that
> > is NOT type-dependent
>
> Using that logic swap is not tependent either. What the qualification
> changes? The arguments make the expression dependent.

No, the arguments are only considered for unqualified names, not
for qualified names.

> >, so from general rules, it makes sense it be
> > bound at the point of definition.
>
> I fail to see what is that sense right now. In case of swap I have
> specialisations. Those will be defined _after_ this template. And I
> expect those used.

I think that's okay -- see 14.6.4.1p1. I believe that in the case
you're concerned about, the point of instantiation of swap will be
at the point of instantiation of the containing specialization,
which will be after your explicit specializations.

> And forget std::swap, think N::foo. I have a bunch of overloaded functions
> in namespace N. (Possibly also a template.) I want the correct candidate
> picked for foo. How that can be found at definition of the general
template?

They have to be visible from the definition. (As I mentioned, the
explicit specializations can come after the definition, but
ordinary overloads must be visible before the definition.) To me,
this makes sense. If you write "N::foo" inside your template, I
would expect that N and foo would be declared before the template
definition. Overload resolution, of course, is done using the
actual argument types in the specialization; it's just choosing
from the overloads visible at the point of the definition.

> > sounds like you want ADL :-)
>
> No, I want the regular lookup, just at the point of instantiation, not at
> definition.

As I mentioned above, the Committee decided that doing ordinary
lookup at the point of definition was too hard. This was part
of the Stockholm compromise that allowed the Committee to agree
on separate compilation of templates ("export").

Consider a template definition in translation unit A. Clearly
references to other things in A must be resolved by ordinary
lexical lookup, so the compiler must essentially compile the
specialization of the template in the context of A, just as if
it were an ordinary function.

Equally obviously, some references from the template
specialization can refer to things declared in translation
unit B, where its point of instantiation occurs. Merging the
entire context of the point of instantiation into the
definition context would be difficult and expensive (expecially
if you have nested instantiations, where a given specialization
might cause instantiation of another template, which might
itself cause another instantion, to an arbitrary depth of
recursion).

The compromise that was reached was to say that lexical lookup
would occur only in the definition context; only ADL would be
performed in the instantiation context. Since qualified
function names do not participate in ADL, any arguments in a
call to a qualified name are ignored in determining whether a
qualified name is dependent or not.

> > Because you missed 14.6.2.2/3
> >
> > An id-expression is type-dependent if it contains:
> > -- an identifier that was declared with a dependent type,
> > -- a template-id that is dependent,
> > -- a conversion-function-id that specifies a dependent type,
> > -- a nested-name-specifier that contains a class-name that names a
> > dependent type.
>
> This part says 'if', not 'if and only if'. So that does not add to
> _exceptional_ cases. Just lists some explicit cases of dependent
> id-expressions in my intrpretation.
>
> Possibly that's the wrong interpretation.

Yes; this list is intended to be exhaustive. An id-expression is
only dependent if it satisfies one of those criteria. The
function call expression of which such an id-expression is a part
will be dependent if any of its argument expressions are, but that
doesn't affect the lookup of the names in the id-expression. (The
arguments only affect the lookup of an unqualified function name
because of the explicit provision in 14.6.2p1.)

-- William M. Miller

William M. Miller

unread,
May 21, 2003, 3:28:24 PM5/21/03
to
"James Kanze" <ka...@gabi-soft.de> wrote in message
news:d6651fb6.03052...@posting.google.com...

>
> Just to be sure I understand what is going on, if I write:
>
> void f( int ) { std::cout << "int\n" ; }
> void f( long ) { std::cout << "long\n" ; }
>
> template< typename T >
> class C {
> public:
> C::C() { ::f( T() ) ; }
> } ;
>
> void f( char ) { std::cout << "char\n" ; }
>
> int
> main()
> {
> C<char> aC ;
> return 0 ;
> }
>
> The output should be "int", and not "char". In other words, the
> overload set is fixed at template definition, although the overload
> resolution cannot actually take place until instantiation.

That's correct. See the example in 14.6.3 -- even though it's
an unqualified name there and qualified in your example, in
both cases it's a non-dependent name lookup that's done, so the
outcome is the same.

-- William M. Miller

Terje Slettebø

unread,
May 22, 2003, 1:01:04 AM5/22/03
to
"Daveed Vandevoorde" <goo...@vandevoorde.com> wrote in message
news:52f2f9cd.03052...@posting.google.com...

> pa...@lib.hu ("Balog Pal") wrote:
>
> > I put general purpose templates (stuff like swap) in a common file,
that is
> > included early in every file.
> > Actual types are defined much later, functions using them even later.
How
> > am I supposed to use namespaces to deal with this thing?
>
> Well, if your std::swap is in scope already, there is no
> problem. You'll still pick up specializations that appear
> later on (because those are not selected by lookup), but
> without ADL you won't pick up later std::swap overloads.

Well, that's ok, as you're not allowed to overload names in the standard
library, anyway. ;)

That leaves specialisation, although without partial specialisation of
function templates, you can't make a swap for a template type, e.g.:

// Not legal C++

namespace std
{
template<class T>
void swap<my_type<T>, my_type<T> >(...) { ... }
}

Although there's a proposal for this...
(http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2001/n1295.htm). This
link appears messed up, though, as it gives another document. Anyway, the
paper is, "Partial Specialization of Function Templates" by Peter Dimov. I
found it in Google's cache, however
(http://216.239.57.100/search?q=cache:ThsG0C8TKyAJ:std.dkuug.dk/jtc1/sc22/wg
21/docs/papers/2001/n1295.htm).


Regards,

Terje

Peter Dimov

unread,
May 22, 2003, 9:01:30 AM5/22/03
to
tsle...@chello.no.nospam ("Terje SlettebÅ™") wrote in message news:<ZKSya.7957$KF1.134230@amstwist00>...

> "Daveed Vandevoorde" <goo...@vandevoorde.com> wrote in message
> news:52f2f9cd.03052...@posting.google.com...
> > pa...@lib.hu ("Balog Pal") wrote:
> >
> > > I put general purpose templates (stuff like swap) in a common file,
> that is
> > > included early in every file.
> > > Actual types are defined much later, functions using them even later.
> How
> > > am I supposed to use namespaces to deal with this thing?
> >
> > Well, if your std::swap is in scope already, there is no
> > problem. You'll still pick up specializations that appear
> > later on (because those are not selected by lookup), but
> > without ADL you won't pick up later std::swap overloads.
>
> Well, that's ok, as you're not allowed to overload names in the standard
> library, anyway. ;)

But the standard library is. For example, <vector> contains an
overload for std::swap. This means that

#include <vector>
#include <algorithm>

is different than

#include <algorithm>
#include <vector>

Nifty, huh?

Dag Henriksson

unread,
May 22, 2003, 9:01:39 AM5/22/03
to
"James Kanze" <ka...@gabi-soft.de> wrote in message
news:d6651fb6.03052...@posting.google.com...

> Just to be sure I understand what is going on, if I write:


>
> void f( int ) { std::cout << "int\n" ; }
> void f( long ) { std::cout << "long\n" ; }
>
> template< typename T >
> class C {
> public:
> C::C() { ::f( T() ) ; }
> } ;
>
> void f( char ) { std::cout << "char\n" ; }
>
> int
> main()
> {
> C<char> aC ;
> return 0 ;
> }
>
> The output should be "int", and not "char". In other words, the

Yes, and it should be that even if you write
C() { f( T() ) ; }

See 14.6.4p1

--
Dag Henriksson

Thomas Witt

unread,
May 22, 2003, 11:14:25 AM5/22/03
to

Hi,

Peter Dimov wrote:
> tsle...@chello.no.nospam ("Terje Slettebø") wrote in message news:<ZKSya.7957$KF1.134230@amstwist00>...


>>Well, that's ok, as you're not allowed to overload names in the standard
>>library, anyway. ;)
>
>
> But the standard library is. For example, <vector> contains an
> overload for std::swap. This means that
>
> #include <vector>
> #include <algorithm>
>
> is different than
>
> #include <algorithm>
> #include <vector>
>
> Nifty, huh?

This starts to get scary.

Thomas

--
Dipl.-Ing. Thomas Witt
Institut fuer Verkehrswesen, Eisenbahnbau und -betrieb, Universitaet
Hannover
voice: +49(0) 511 762 - 4273, fax: +49(0) 511 762-3001
http://www.ive.uni-hannover.de

Terje Slettebø

unread,
May 22, 2003, 1:42:17 PM5/22/03
to
"Peter Dimov" <pdi...@mmltd.net> wrote in message
news:7dc3b1ea.03052...@posting.google.com...

*wince*

I guess there was a reason for your proposal for partial specialisation of
function templates. :) The above makes all the more reason to use
specialisation rather than overloading for this, as it's not
order-dependent.


Regards,

Terje

Gabriel Dos Reis

unread,
May 22, 2003, 1:42:33 PM5/22/03
to
pdi...@mmltd.net (Peter Dimov) writes:

[...]

| #include <vector>
| #include <algorithm>
|
| is different than

^^

| #include <algorithm>
| #include <vector>

Not is. But *may*.

--
Gabriel Dos Reis, g...@integrable-solutions.net

---

LLeweLLyn

unread,
May 22, 2003, 2:02:14 PM5/22/03
to
pdi...@mmltd.net (Peter Dimov) writes:

> tsle...@chello.no.nospam ("Terje Slettebø") wrote in message


> news:<ZKSya.7957$KF1.134230@amstwist00>...
> > "Daveed Vandevoorde" <goo...@vandevoorde.com> wrote in message
> > news:52f2f9cd.03052...@posting.google.com...
> > > pa...@lib.hu ("Balog Pal") wrote:
> > >
> > > > I put general purpose templates (stuff like swap) in a common file,
> > that is
> > > > included early in every file.
> > > > Actual types are defined much later, functions using them even later.
> > How
> > > > am I supposed to use namespaces to deal with this thing?
> > >
> > > Well, if your std::swap is in scope already, there is no
> > > problem. You'll still pick up specializations that appear
> > > later on (because those are not selected by lookup), but
> > > without ADL you won't pick up later std::swap overloads.
> >
> > Well, that's ok, as you're not allowed to overload names in the standard
> > library, anyway. ;)
>
> But the standard library is. For example, <vector> contains an
> overload for std::swap. This means that
>
> #include <vector>
> #include <algorithm>
>
> is different than
>
> #include <algorithm>
> #include <vector>
>
> Nifty, huh?

I thought standard headers were supposed have a meaning independent of
their order of inclusion. I think 17.4.2.1/2 supports this:

A translation unit may include library headers in any order
(clause 2). Each may be included more than once, with no effect
different from being included exactly once, except that the effect
of including either <cassert> or <assert.h> depends each time on
the lexically current definition of NDEBUG. (161)

If your interpretation of the lookup of std::swap is correct, and my
interpretation of 17.4.2.1/2 is correct, I think a DR is in order.

Balog Pal

unread,
May 22, 2003, 2:38:53 PM5/22/03
to
Okey, thanks everyone, I learned a lot!

Paul

Gabriel Dos Reis

unread,
May 22, 2003, 2:40:36 PM5/22/03
to
ka...@gabi-soft.de (James Kanze) writes:

[...]

| > >From various discussions I've seen on committee reflectors, that
| > always appeared to me as an intended behaviour.
|
| I suspect that it is half and half.

Ask the people who wrote that part. I'm pretty sure they will tell
you it was a deliberate decision.

[...]

| Just to be sure I understand what is going on, if I write:
|
| void f( int ) { std::cout << "int\n" ; }
| void f( long ) { std::cout << "long\n" ; }
|
| template< typename T >
| class C {
| public:
| C::C() { ::f( T() ) ; }
| } ;
|
| void f( char ) { std::cout << "char\n" ; }
|
| int
| main()
| {
| C<char> aC ;
| return 0 ;
| }
|
| The output should be "int", and not "char".

Yes. That should output the same thing even if you didn't explicilty
qualify f. There are some compilers out there that get that wrong
(GCC-3.2.x is a notable example).

--
Gabriel Dos Reis, g...@integrable-solutions.net

---

Howard Hinnant

unread,
May 22, 2003, 2:47:34 PM5/22/03
to
In article <m14r3ma...@localhost.localdomain>, LLeweLLyn
<llewe...@xmission.dot.com> wrote:

| > But the standard library is. For example, <vector> contains an
| > overload for std::swap. This means that
| >
| > #include <vector>
| > #include <algorithm>
| >
| > is different than
| >
| > #include <algorithm>
| > #include <vector>
| >
| > Nifty, huh?
|
| I thought standard headers were supposed have a meaning independent of
| their order of inclusion. I think 17.4.2.1/2 supports this:
|
| A translation unit may include library headers in any order
| (clause 2). Each may be included more than once, with no effect
| different from being included exactly once, except that the effect
| of including either <cassert> or <assert.h> depends each time on
| the lexically current definition of NDEBUG. (161)
|
| If your interpretation of the lookup of std::swap is correct, and my
| interpretation of 17.4.2.1/2 is correct, I think a DR is in order.

This is fixed in:

http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1439.htm

which hasn't been accepted yet, but the lwg has informally agreed with
the general approach.

--
Howard Hinnant
Metrowerks

Gabriel Dos Reis

unread,
May 25, 2003, 10:33:17 AM5/25/03
to
tsle...@chello.no.nospam ("Terje Slettebø") writes:

| I guess there was a reason for your proposal for partial specialisation of
| function templates. :) The above makes all the more reason to use
| specialisation rather than overloading for this, as it's not
| order-dependent.

But it can be translation unit dependent.

--
Gabriel Dos Reis, g...@integrable-solutions.net

---

Terje Slettebø

unread,
May 25, 2003, 8:45:47 PM5/25/03
to
"Gabriel Dos Reis" <g...@integrable-solutions.net> wrote in message
news:m3d6ia6...@uniton.integrable-solutions.net...

tsle...@chello.no.nospam ("Terje Slettebø") writes:

>| I guess there was a reason for your proposal for partial specialisation
of
>| function templates. :) The above makes all the more reason to use
>| specialisation rather than overloading for this, as it's not
>| order-dependent.

>But it can be translation unit dependent.

In what way? Of course, if the compiler hasn't seen the specialisation,
before it's bound at the point of instantiation, it can't use it.


Regards,

Terje

Gabriel Dos Reis

unread,
May 27, 2003, 1:13:18 PM5/27/03
to
tsle...@chello.no.nospam ("Terje Slettebø") writes:

| "Gabriel Dos Reis" <g...@integrable-solutions.net> wrote in message
| news:m3d6ia6...@uniton.integrable-solutions.net...
| tsle...@chello.no.nospam ("Terje Slettebø") writes:
|
| >| I guess there was a reason for your proposal for partial specialisation
| of
| >| function templates. :) The above makes all the more reason to use
| >| specialisation rather than overloading for this, as it's not
| >| order-dependent.
|
| >But it can be translation unit dependent.
|
| In what way? Of course, if the compiler hasn't seen the specialisation,
| before it's bound at the point of instantiation, it can't use it.

So, you answer your own question: The set of specializations ought
to be the same in every translation unit in a consistent manner,
or else bad things may silently happen.

--
Gabriel Dos Reis, g...@integrable-solutions.net

---

faisal vali

unread,
May 27, 2003, 1:19:00 PM5/27/03
to

"Terje Slettebø" wrote:
>
<snip>


>
> Although there's a proposal for this...
> (http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2001/n1295.htm). This
> link appears messed up, though, as it gives another document. Anyway, the
> paper is, "Partial Specialization of Function Templates" by Peter Dimov.


Does anyone know why this link is messed up?

If no decision has been made by the committee yet, perhaps this proposal
needs to be resubmitted (like the local classes proposal had to be
resubmitted)?

regards,
Faisal Vali

James Kanze

unread,
Jun 15, 2003, 6:13:53 PM6/15/03
to
dag.hen...@quidsoft.se ("Dag Henriksson") writes:

|> "James Kanze" <ka...@gabi-soft.de> wrote in message
|> news:d6651fb6.03052...@posting.google.com...

|> > Just to be sure I understand what is going on, if I write:

|> > void f( int ) { std::cout << "int\n" ; }
|> > void f( long ) { std::cout << "long\n" ; }

|> > template< typename T >
|> > class C {
|> > public:
|> > C::C() { ::f( T() ) ; }
|> > } ;

|> > void f( char ) { std::cout << "char\n" ; }

|> > int
|> > main()
|> > {
|> > C<char> aC ;
|> > return 0 ;
|> > }

|> > The output should be "int", and not "char". In other words, the

|> Yes, and it should be that even if you write
|> C() { f( T() ) ; }

|> See 14.6.4p1

Now I'm really confused. If I don't use the qualifier, why doesn't
14.6.2 apply? I have an "expression of the form:

postfix-expression ( expression-list[opt] )

where the postfix-expression is an identifier", and T() is a type
dependant expression, and so I would expect that "the identifier
denotes a dependant name".

And if the name is dependant, shouldn't look up be deferred until the
point of instantiation?

--
James Kanze mailto:ka...@gabi-soft.fr


Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

11 rue de Rambouillet, 78460 Chevreuse, France Tel. +33 1 41 89 80 93

James Kanze

unread,
Jun 16, 2003, 3:40:03 PM6/16/03
to
wi...@ive.uni-hannover.de (Thomas Witt) writes:

|> Peter Dimov wrote:
|> > tsle...@chello.no.nospam ("Terje Slettebø") wrote in message news:<ZKSya.7957$KF1.134230@amstwist00>...
|> >>Well, that's ok, as you're not allowed to overload names in the standard
|> >>library, anyway. ;)
|> > But the standard library is. For example, <vector> contains an
|> > overload for std::swap. This means that
|> > #include <vector>
|> > #include <algorithm>
|> > is different than
|> > #include <algorithm>
|> > #include <vector>
|> > Nifty, huh?

|> This starts to get scary.

Starts? I consider myself probably better than average, and I'm
totally incapable of understanding what happens in name lookup in
templates more than half the time. I rather suspect that we've ended
up with something so complicated that it cannot be safely used in real
projects.

--
James Kanze mailto:ka...@gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France Tel. +33 1 41 89 80 93

---

William M. Miller

unread,
Jun 16, 2003, 9:39:26 PM6/16/03
to
"James Kanze" <ka...@alex.gabi-soft.fr> wrote in message
news:86ptlfc...@alex.gabi-soft.fr...

Yes, that's true. However, the lookup of a dependent name involves
only:

- Declarations that are visible at the point of definition of
the template

- Declarations from namespaces associated with the types of the
function arguments both from the instantiation context
(14.6.4.1) and from the definition context

(14.6.4p1). In this example, the types of the function arguments
are all fundamental types, which have no associated classes or
namespaces (3.4.2p2), so the only declarations available for
consideration are the ones visible at the point of definition. It
would be different if you had used a class type instead of char.

-- William M. Miller

Gabriel Dos Reis

unread,
Jun 20, 2003, 3:34:17 PM6/20/03
to
ka...@alex.gabi-soft.fr (James Kanze) writes:

Yes, "f" is considered to be a dependent name.

| And if the name is dependant, shouldn't look up be deferred until the
| point of instantiation?

Dependent name lookup resolution is explained in 14.6.4/1 which says:

In resolving dependent names, names from the following sources are
considered:
-- Declarations that are visible at the point of definition of the
template.
-- Declarations from namespaces associated with the types of the
function arguments both from the instan-tiation context (14.6.4.1)
and from the definition context.

In the above example, at the point of definition, ordinary name lookup
finds

void f(int);
void f(long);

Because, the set of associated namespaces of the template argument
"char" is empty, name lookup in the instantiation context sees
nothing. Hence Dag's comment.

--
Gabriel Dos Reis, g...@integrable-solutions.net

---

Terje Slettebø

unread,
Jun 20, 2003, 3:34:42 PM6/20/03
to
"James Kanze" <ka...@alex.gabi-soft.fr> wrote in message
news:86ptlfc...@alex.gabi-soft.fr...

As Daveed Vandevoorde said in another posting, dependent names are
looked up using both ordinary lookup (OL) and ADL. The OL happens in the
definition context, while the ADL happens in the instantiation context.
As int is used, there's no associated namespaces or classes, so the ADL
lookup doesn't return anything, and the binding at the OL is used.

It becomes even more clear if you remove f(int) and f(long), and it will
then give an error about undefined "f". Also, try using a UDT for
instantiation, instead, and an overloaded function for it, defined after
the class template but before main. It should then be selected.

I guess what is confusing, here, is that 14.6.2/1 says: "Such names are
unbound and are looked up at the point of the template instantiation
(14.6.4.1) in both the context of the template definition and the
context of the point of instantiation."

However, when we look at the paragraph about dependent name resolution
(14.6.4/1), it says:

"In resolving dependent names, names from the following sources are
considered:

- Declarations that are visible at the point of definition of the
template.

- Declarations from namespaces associated with the types of the function

arguments both from the instantiation context (14.6.4.1) and from the
definition context."

So it appears that the lookup in 14.6.2/1 refers to the OL in the
definition context, and ADL in the instantiation context.


Regards,

Terje

David Abrahams

unread,
Jun 20, 2003, 3:35:24 PM6/20/03
to
ka...@alex.gabi-soft.fr (James Kanze) writes:

> wi...@ive.uni-hannover.de (Thomas Witt) writes:
>
> |> Peter Dimov wrote:
> |> > tsle...@chello.no.nospam ("Terje Slettebø") wrote in message news:<ZKSya.7957$KF1.134230@amstwist00>...
> |> >>Well, that's ok, as you're not allowed to overload names in the standard
> |> >>library, anyway. ;)
> |> > But the standard library is. For example, <vector> contains an
> |> > overload for std::swap. This means that
> |> > #include <vector>
> |> > #include <algorithm>
> |> > is different than
> |> > #include <algorithm>
> |> > #include <vector>
> |> > Nifty, huh?
>
> |> This starts to get scary.
>
> Starts? I consider myself probably better than average, and I'm
> totally incapable of understanding what happens in name lookup in
> templates more than half the time. I rather suspect that we've ended
> up with something so complicated that it cannot be safely used in real
> projects.

P'raps so. I wrote a paper about some of these problems:
http://www.boost-consulting.com/writing/qn.html

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

faisal vali

unread,
Jun 23, 2003, 11:42:35 PM6/23/03
to

Terje Slettebø wrote:
>
<snip>

> As Daveed Vandevoorde said in another posting, dependent names are
> looked up using both ordinary lookup (OL) and ADL. The OL happens in the
> definition context, while the ADL happens in the instantiation context.
> As int is used, there's no associated namespaces or classes, so the ADL
> lookup doesn't return anything, and the binding at the OL is used.

It was my understanding that ADL also occurs at the point of definition
along with OL.

Consider the following example:

namespace B { struct S; }

namespace A
{
struct S { };
struct R { };
void f(S); // -- 0
void f(int, S, R); // -- 1
}

namespace B
{
using namespace A;

struct S { };
struct R { };
void f(char, S, R); // -- 2
template<class T1, class T2, class T3> void f(T1,T2,T3); // -- 3
}

struct S { };
struct R { };

void f(bool, S, R); // -- 4

template<class PT, class UDT>
void foo()
{
f(PT(), B::S(), UDT());

}

namespace A
{
void f(int, B::S ,int); // -- 5
}

void f(int, B::S, int); // -- 6

namespace B
{
void f(int, int, int); // -- 7
}

void f(int, B::S, R); // -- 8

The definition context adds the following candidates to the overload
set:

a) 4 -> OL
b) 2 -> ADL
c) 3 -> ADL


foo<char,B::R>();
-- POI lookup will perform ONLY an ADL, and so the following
candidates are added:
d) 7 -> ADL
-- OR is performed and 2 is selected as the best match

foo<int,int>();
-- no new namepsaces added, so no ADL
-- (even though 6 is a non-templt exact match and OL at POI would have
added this)
-- 3 is selected

foo<int,A::R>();
-- new candidates added due to ADL:
d) 0 // from A
e) 1 // from A
f) 5 // from A
g) 7 // from B
-- OR is performed and 3 is selected again (I think)

foo<int,R>();
-- new candidates added due to ADL:
d) 7 // from B
e) 6 // from global namespace
f) 8 // from global namespace
-- OR selects 8 (since non-template exact match)


I think there are some more interesting scenarios lurking in the above
example...
but, anyways, as I was saying, ADL is performed both at POD and POI.
OL is only performed at POD.

Of course I could be wrong, since I'm still figuring this stuff out.

Any comments or corrections are welcome.

regards,
-Faisal Vali

Daveed Vandevoorde

unread,
Jun 24, 2003, 10:02:47 PM6/24/03
to
fv...@eecs.ku.edu (faisal vali) wrote:
[... POD = point of definition ]

> I think there are some more interesting scenarios lurking in the above
> example...
> but, anyways, as I was saying, ADL is performed both at POD and POI.
> OL is only performed at POD.
>
> Of course I could be wrong, since I'm still figuring this stuff out.
>
> Any comments or corrections are welcome.

I didn't study your example, but your statement above it correct.

Daveed

Mirek Fidler

unread,
Jul 20, 2003, 5:27:12 AM7/20/03
to
|> > #include <vector>
|> > #include <algorithm>
|> > is different than
|> > #include <algorithm>
|> > #include <vector>
|> > Nifty, huh?

|> This starts to get scary.

> Starts? I consider myself probably better than average, and I'm
> totally incapable of understanding what happens in name lookup in
> templates more than half the time. I rather suspect that we've ended
> up with something so complicated that it cannot be safely used in real
> projects.

What about sweeping out all this dependent / non-dependent stuff and
return to method older/brokne compilers use anyway, that is deffering
everything to the point instatiation ?

I think that most problems w.r.t. templates are due to the fact that
as (perhaps) last minute change comitee decided that it would be a good
idea to check templates even when they are not instantiated. And perhaps
that it is bad that templates depened on order of declaration.

Well, I am not sure what problems were really solved. Templates
still depend on order of declarations. Compile time checking of
templates sometimes works, but not always.

I really had no problems using compilers that perform just
instatiation-point checks and resolutions. My problems started with
compilers that are compliant....

Mirek

Bo Persson

unread,
Jul 20, 2003, 6:04:17 AM7/20/03
to

""Mirek Fidler"" <c...@volny.cz> wrote...

> |> > #include <vector>
> |> > #include <algorithm>
> |> > is different than
> |> > #include <algorithm>
> |> > #include <vector>
> |> > Nifty, huh?

Only if vector references some of the algorithms without also
including <algorithm>. A nice library wouldn't do that, would it?

>
> |> This starts to get scary.
>
> > Starts? I consider myself probably better than average, and I'm
> > totally incapable of understanding what happens in name lookup in
> > templates more than half the time. I rather suspect that we've
ended
> > up with something so complicated that it cannot be safely used in
real
> > projects.
>
> What about sweeping out all this dependent / non-dependent stuff
and
> return to method older/brokne compilers use anyway, that is
deffering
> everything to the point instatiation ?

That just moves the "problem" to your implementation files. What if
*they* also include different headers?

Also, it is important for export that the compiler considers what is
visible in the template's implementation file.

>
> I think that most problems w.r.t. templates are due to the fact
that
> as (perhaps) last minute change comitee decided that it would be a
good
> idea to check templates even when they are not instantiated. And
perhaps
> that it is bad that templates depened on order of declaration.

So does other code. Even ordinary functions work differently depending
on the number of overloads visible.

Consider the functions std::abs() being declared in <complex>,
<cstdlib>, and several times in <cmath>. What happens to the call
abs(1.0) depends on which of these are visible...

Should we get rid of overloads as well?

>
> Well, I am not sure what problems were really solved. Templates
> still depend on order of declarations.

Not only templates!


Bo Persson
bo...@telia.com

Mirek Fidler

unread,
Jul 20, 2003, 8:14:12 AM7/20/03
to
> > What about sweeping out all this dependent / non-dependent stuff
> and
> > return to method older/brokne compilers use anyway, that is
> deffering
> > everything to the point instatiation ?
>
> That just moves the "problem" to your implementation files. What if
> *they* also include different headers?

Yeas, but I think I can rather handle this than all that
dependent/non-dependent names lookup complications....

I believe that without this, all chapter 14 would be reduced by 50%
and even moderately good programmer as me could finally use templates
without danger that more conforming C++ implementation will break all
his code again...

> Also, it is important for export that the compiler considers what is
> visible in the template's implementation file.

You mean that "export" that no compiler supported for 5 years after
the standard release and nobody ever needed ?!

> > Well, I am not sure what problems were really solved. Templates
> > still depend on order of declarations.
>
> Not only templates!

Hey, I agree with this. What I wanted to say is that if this problem
is present in other code, why in the world standard tries to be smarter
than is needed ?

Mirek

Gabriel Dos Reis

unread,
Jul 20, 2003, 5:23:30 PM7/20/03
to
c...@volny.cz ("Mirek Fidler") writes:

| I think that most problems w.r.t. templates are due to the fact that
| as (perhaps) last minute change comitee decided that it would be a good
| idea to check templates even when they are not instantiated. And perhaps
| that it is bad that templates depened on order of declaration.

I don't know where and when it started, I've been seeing confusion or
misinformation like the above being repeated more than often.

The notion of 2-phase name lookup was already considered in the dark
ages. The main difference with what was considered at the time is
that now not just operators may be dependent, but also functions used
in certain way and that in meantime we've got Argument Dependent Name
Lookup -- characterizing ADL as a "template baby" is a good recipe for
confusion.

At the time they were speaking of "bound symbols" (roughly what we call
"dependent name" nowadays), and "free symbols" ("non-dependent name"
in contemporary terms). Free symbols were supposed to be resolved in
the context of the template definition, and the bound symbols were
supposed to be resolved in the instantiation context.

http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/1992/N0209.ps

I find the above mentioned paper very instructive on understanding
what were the general design criteria and the philophical basis.

--
Gabriel Dos Reis, g...@integrable-solutions.net

---

Mirek Fidler

unread,
Jul 21, 2003, 1:54:44 AM7/21/03
to
> | I think that most problems w.r.t. templates are due to the fact
that
> | as (perhaps) last minute change comitee decided that it would be a
good
> | idea to check templates even when they are not instantiated. And
perhaps
> | that it is bad that templates depened on order of declaration.
>
> I don't know where and when it started, I've been seeing confusion or
> misinformation like the above being repeated more than often.

I must apologize, I do not know exact history. It is just it seems
so as it would be last minute change, given all chapter 14 content and
endless confusion about it...

Mirek

Gabriel Dos Reis

unread,
Jul 21, 2003, 2:32:24 PM7/21/03
to
c...@volny.cz ("Mirek Fidler") writes:

| > > Well, I am not sure what problems were really solved. Templates
| > > still depend on order of declarations.
| >
| > Not only templates!
|
| Hey, I agree with this. What I wanted to say is that if this problem
| is present in other code, why in the world standard tries to be smarter
| than is needed ?

I've seen no evidence that the "standard tires to be smarter
than is needed" as far as the template machinery is concerned. On the
other hand, I've seen repeated assertions with no technical foundation.

--
Gabriel Dos Reis, g...@integrable-solutions.net

---

Mirek Fidler

unread,
Jul 21, 2003, 4:34:27 PM7/21/03
to
> | Hey, I agree with this. What I wanted to say is that if this
problem
> | is present in other code, why in the world standard tries to be
smarter
> | than is needed ?
>
> I've seen no evidence that the "standard tires to be smarter
> than is needed" as far as the template machinery is concerned. On the
> other hand, I've seen repeated assertions with no technical
foundation.

What I wanted to say is that I do not see any advantage that
two-phase lookup would give to me as opposed to simple
instatiation-point lookup.

If there are any advantages I do not see yet, please go on and show
me them.

Mirek

ka...@gabi-soft.fr

unread,
Jul 23, 2003, 11:37:35 AM7/23/03
to
c...@volny.cz ("Mirek Fidler") wrote in message
news:<bff24j$du3fh$1...@ID-198693.news.uni-berlin.de>...

> > | I think that most problems w.r.t. templates are due to the
> > | fact that as (perhaps) last minute change comitee decided that it
> > | would be a good idea to check templates even when they are not
> > | instantiated. And perhaps that it is bad that templates depened on
> > | order of declaration.

> > I don't know where and when it started, I've been seeing confusion
> > or misinformation like the above being repeated more than often.

> I must apologize, I do not know exact history. It is just it seems
> so as it would be last minute change, given all chapter 14 content and
> endless confusion about it...

I guess it depends on what you mean by "last minute change". Chapter 14
didn't get its final wording into very late in the game. That doesn't
mean that nothing in it was discussed or considered earlier. It does
mean that compiler implementors couldn't get started earlier, with the
results that even today, no two compilers seem to implement exactly the
same thing. (As Gaby correctly points out, a lot of the changes are due
to the addition of namespaces. Let's face it, no one had any concrete
experience of how namespaces would work with two phase lookup in
templates, given that both were complete innovations by the committee,
so some experimentation was necessary.)

It's probably worth pointing out that most of the discussion outside of
the committee centered on all of the new things you could do with
standard C++. Two phase lookup doesn't add any new functionality, so it
didn't get any lead articles in C++ Report. Even today, I suspect that
most older programmers first learn about it when it hits them. This is
a shame, but I don't see what could have been done about it.

--
James Kanze GABI Software mailto:ka...@gabi-soft.fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

Mirek Fidler

unread,
Jul 23, 2003, 3:02:58 PM7/23/03
to
> Two phase lookup doesn't add any new functionality, so it
> didn't get any lead articles in C++ Report. Even today, I suspect
that
> most older programmers first learn about it when it hits them. This
is
> a shame, but I don't see what could have been done about it.

Well, if it does not add any new functionality (just removes some
useful possibilities), is it really needed ?

Are there any *real* problem that are solved by two-phase lookup ?
Only benefit I can see so far is the possibility to detect some bugs at
compile time, in case that concrete thing does not get instantiated, but
such bugs seldom has any influence on code correctness. Are there any
any other *practical* benefits of two-phase lookup as opposed to single
instantiation point lookup ? (as implemented in e.g. GCC)

Mirek

ka...@gabi-soft.fr

unread,
Jul 23, 2003, 3:04:43 PM7/23/03
to
g...@integrable-solutions.net (Gabriel Dos Reis) wrote in message
news:<m3smp12...@uniton.integrable-solutions.net>...

> c...@volny.cz ("Mirek Fidler") writes:

> | > > Well, I am not sure what problems were really
> | > > solved. Templates still depend on order of declarations.

> | > Not only templates!

> | Hey, I agree with this. What I wanted to say is that if this
> | problem is present in other code, why in the world standard tries to
> | be smarter than is needed ?

> I've seen no evidence that the "standard tires to be smarter than is
> needed" as far as the template machinery is concerned. On the other
> hand, I've seen repeated assertions with no technical foundation.

I don't think that there can be a "technical foundation", since the
problem isn't really technical. In introducing two phase look-up, the
standard introduced a change with regards to existing practice. The
motivation for the change was, as far as I can tell, to reduce the risk
of "name hijacking" -- of the template instantiation accidentally
picking up a local name at the instantiation point. The means involved
were:

- separate names into dependant and non-dependant,
- do all non-dependant lookup in the template definition context, and
- do dependant lookup globally in the definition context, and using
only ADL in the instantiation context.

As with any change, there are costs, and there are (hopefully)
benefits. Not all of which are technical. On the costs side:

Added complexity for the user:
There are really two aspects here: it is not trivially obvious what
is dependant, and what isn't, so sometimes the compiler will not
find a name I expect it to (because it is using dependant lookup),
and the fact that at the instantiation context, only ADL lookup is
used (lack of orthogonality in the lookup rules -- again, the
compiler fails to find a name I expect it to find.

If the names are to be divided into two categories, for different
types of look-up, I'd much prefer that the division be more
explicit.

Added complexity for the implementor:
I'm just guessing about this, but I cannot imagine how two phase
lookup could fail to more complex than the older situation.

This has repercusions for the user as well: at present, it is
difficult to find two compilers which do exactly the same thing.

Breaks existing code:
Also a problem, although I think that most, if not all cases where
the code is broken will result in a compiler error. While it isn't
difficult to construct cases where code silently breaks, I don't
think that they are very frequent in practice.

The price is, in sum, very high.

As for the benefits, it does reduce the risk of name hijacking. The
potential problem is real, but I've seen no evidence, or for that
matter, no real indication, that it is anything but potential. In
practice, it isn't a problem in small projects, and it is a general
problem, not limited to templates in large projects, with the result
that any successful large project already has some political mechanisms
for dealing with the problem. (In my own experience, mostly in projects
of more than 500 KLoc, I've only seen one case of a name conflict. And
that was due to a macro in an X11 header -- two phase lookup doesn't
help with regards to macros.)

In sum, two phase look-up is a very expensive solution to a problem that
didn't exist in practice.

--
James Kanze GABI Software mailto:ka...@gabi-soft.fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung


11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

---

Gabriel Dos Reis

unread,
Jul 23, 2003, 10:11:29 PM7/23/03
to
ka...@gabi-soft.fr writes:

| It's probably worth pointing out that most of the discussion outside of
| the committee centered on all of the new things you could do with
| standard C++. Two phase lookup doesn't add any new functionality, so it
| didn't get any lead articles in C++ Report. Even today, I suspect that
| most older programmers first learn about it when it hits them. This is
| a shame, but I don't see what could have been done about it.

Better explanation outside the inner circle of template gurus?

--
Gabriel Dos Reis, g...@integrable-solutions.net

---

Daveed Vandevoorde

unread,
Jul 23, 2003, 10:13:53 PM7/23/03
to
c...@volny.cz ("Mirek Fidler") wrote:
> > | Hey, I agree with this. What I wanted to say is that if this
> problem
> > | is present in other code, why in the world standard tries to be
> smarter
> > | than is needed ?
> >
> > I've seen no evidence that the "standard tires to be smarter
> > than is needed" as far as the template machinery is concerned. On the
> > other hand, I've seen repeated assertions with no technical
> foundation.
>
> What I wanted to say is that I do not see any advantage that
> two-phase lookup would give to me as opposed to simple
> instatiation-point lookup.
>
> If there are any advantages I do not see yet, please go on and show
> me them.

Two-phase lookup helps address three problems:

(a) Parsing templates in their generic form.

Parsing " X * p;" requires the knowledge of whether X is a type
or not. If you delay all your lookups to the point of instantiation
you cannot parse this thing in contexts that allow both declarations
and expressions (such as function definitions).

The first compiler to implement a form of two-phase name lookup
was the HP aC++ compiler (it wasn't quite the standard scheme,
but it was fairly close; early 1997). When the aC++ engineers fed
popular template libraries to the compiler, they found that _all_ of
them contained basic syntax errors that had never been detected by
other compilers. (Which means that parts of these libraries had
never been instantiated even though they had been around for years!)

Some very recent compilers still accept the following code:

template<typename T> void f() {
X * p
g()
}

(the missing semicolons are intentional).


(b) Accidental name capture.

(See also a post by James Kanze in this thread.)

Basically, the template writer gets more control over some of the names
used in a template definition since they cannot be hijacked by the
instantiation context.

(c) A template separation model.

In a separation model (unlike an inclusion model), the definition context
is not accessible for ordinary lookup during instantiation (since the
definition has been compiled already).

IOW, two-phase lookup was essential for "export."


("C++ Templates: The Complete Guide" introduces many of these issues,
as well as some of the history.)

Daveed

Hyman Rosen

unread,
Jul 24, 2003, 2:05:47 PM7/24/03
to
Mirek Fidler wrote:
> Are there any *real* problem that are solved by two-phase lookup ?

How to define what may legally appear inside a template.

ka...@gabi-soft.fr

unread,
Jul 25, 2003, 11:31:42 AM7/25/03
to
g...@integrable-solutions.net (Gabriel Dos Reis) wrote in message
news:<m3llupi...@uniton.integrable-solutions.net>...
> ka...@gabi-soft.fr writes:

> | It's probably worth pointing out that most of the discussion outside
> | of the committee centered on all of the new things you could do with
> | standard C++. Two phase lookup doesn't add any new functionality,
> | so it didn't get any lead articles in C++ Report. Even today, I
> | suspect that most older programmers first learn about it when it
> | hits them. This is a shame, but I don't see what could have been
> | done about it.

> Better explanation outside the inner circle of template gurus?

Probably. As I said, in this respect, it suffers from the problem of
not being sexy enough. When changes in template handling were discussed
outside of the working group concerned, what got the real mention was
things like member templates, partial specialization, template
templates, etc. All features that let you do something that wasn't
possible otherwise. Whereas the only real argument I've heard for two
phase name lookup (until David's posting here) was that it might prevent
name hijacking. And let's face it: what's sexy about preventing errors?

My own opinion is that the costs are higher than the benefits. But my
own analysis is largely based on the one benefit that I was aware of:
avoiding name hijacking. I'll have to think a bit about the other
points David made. Still, my opinion is based on the very high cost
that I perceive with regards to understandability -- if it were somehoe
intuitively obvious which names were dependant, for example, the cost
would drop considerably. And that might be more an education problem
(related to the lack of discussion) than anything else.

I (like many other older programmers) am also bothered by the fact that
it breaks a lot of my existing code. Again, breaking code should have
been considered a high cost, and should have weighed heavily against two
phase lookup. But here again, more early discussion would have helped.
All of my template code was actually written after the first discussions
concerning two phase lookup in the standards working group, and had I
known that this was a possibility, I would have (hopefully) written my
code so that it worked both ways.

Anyway, whatever the alternatives, I think we have to live with what we
have. I, for one, would certainly NOT suggest removing two phase lookup
now that we have it. I would consider such a suggestion irresponsible.
(Just as I considered other proposals to remove something from the
standard irresponsible.) I wish it were easier to understand, but for
the moment, the only responsible solution I see here is education. I
wish it hadn't broken my code, but at least the breaks result in
compiler errors, which are easily corrected, and not in a change in the
run-time semantics.

--
James Kanze GABI Software mailto:ka...@gabi-soft.fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

---

Daveed Vandevoorde

unread,
Jul 25, 2003, 4:16:40 PM7/25/03
to
c...@volny.cz ("Mirek Fidler") wrote:
[...]

> Are there any *real* problem that are solved by two-phase lookup ?

See also my other posting that lists three broad issues.

> Only benefit I can see so far is the possibility to detect some bugs at
> compile time, in case that concrete thing does not get instantiated, but
> such bugs seldom has any influence on code correctness.

I have found that it has a tremendous impact on my coding cycle:
Discovering a basic syntax error while I develop a template is far
less frustrating than discovering it when I test the whole thing.

Like I said in the other posting: Prior to compilers supporting two-
phase name lookup a large number of template libraries were
shipping with templates that contained basic syntax errors.
A standard-conforming compiler would have saved quite a bit
of embarassment.

> Are there any
> any other *practical* benefits of two-phase lookup as opposed to single
> instantiation point lookup ? (as implemented in e.g. GCC)

It enables separate compilation of templates. That in turn enables
(but does not require) faster build times and non-source object
file representations of templates.

It also enables compiler implementations that represent templates
in parsed form instead of as a token stream. The advantage of
that is that template instantiation becomes a considerably cheaper
(read: faster!) process. Some compilers do this today.

Daveed

Gabriel Dos Reis

unread,
Jul 25, 2003, 8:52:15 PM7/25/03
to
ka...@gabi-soft.fr writes:

[...]

| I (like many other older programmers) am also bothered by the fact that
| it breaks a lot of my existing code.

That is interesting. In which ways does it break them?
I would really like to understand how you wrote them and how trhey are
now broken. I'm not implying you don't have such code, I'm just
curious about the way you wrote them and the sort of assumptions you
made. (I've already seen code not compiling any more with GCC-3.4, but I
tend to think there were too many unspoken assumptions).

| Again, breaking code should have
| been considered a high cost, and should have weighed heavily against two
| phase lookup. But here again, more early discussion would have helped.

"more early" than 1992 would mean?

(The reference I gave is one of the oldest reference publically
reachable, I would not be surprised that discussions related to that
paper started even earlier, bringing us in 1991 or 1990, i.e. when
committee works started).

| All of my template code was actually written after the first discussions
| concerning two phase lookup in the standards working group, and had I
| known that this was a possibility, I would have (hopefully) written my
| code so that it worked both ways.

Just curious: You mean, you never wrote any template code after early
1992?

Let's face it: templates were an experimental feature when proposed
for standardization; as such it was expected that rules would change.

--
Gabriel Dos Reis, g...@integrable-solutions.net

---

Gabriel Dos Reis

unread,
Jul 25, 2003, 8:53:00 PM7/25/03
to
goo...@vandevoorde.com (Daveed Vandevoorde) writes:

[...]

| > Are there any
| > any other *practical* benefits of two-phase lookup as opposed to single
| > instantiation point lookup ? (as implemented in e.g. GCC)
|
| It enables separate compilation of templates.

Maybe it would help if people remember that in 1992, the issue of
separate or not separate compilation of templates was not on
explicilty the table, because the separate compilation of template was
implied as the default (mostly in the mind of the people who wrote the
reference I gave).

[...]

| It also enables compiler implementations that represent templates
| in parsed form instead of as a token stream. The advantage of
| that is that template instantiation becomes a considerably cheaper
| (read: faster!) process. Some compilers do this today.

I wish there were more "communications" on the basics of templates.
Hopefully, your book will fill the gap.

--
Gabriel Dos Reis, g...@integrable-solutions.net

---

Mirek Fidler

unread,
Jul 26, 2003, 3:26:57 PM7/26/03
to
> | I (like many other older programmers) am also bothered by the fact
that
> | it breaks a lot of my existing code.
>
> That is interesting. In which ways does it break them?

Well, I cannot speak for James, but my problems are e.g.

template <class T>
struct Base {
void Foo();
};

template <class T>
struct Derived : Base<T> {
void Bar() { Foo(); } // broken with two-phase lookup
};

Of course I know I can fixit by adding e.g. "this->", but it is no
fun when you have to add hundreds of them.... And it is pretty
unintuitive too !

> made. (I've already seen code not compiling any more with GCC-3.4,
but I
> tend to think there were too many unspoken assumptions).

Probably. Average programmer expects intuitive behaviour. Only a
dozen of experts has time and energy to go through chapter 14 and
understand it. Personally, 20 days ago I have posted some question about
chapter 14 and nobody in both this forum and cl.c++.m was able to
explain what is really happening with my code (see "Using friend
definition for specialization") - posts tend to end with "and this is
where I get lost". Sorry, but this is not a sign of simple, effective
and understandable rules.

So what is left for average programmer ? I believe that only
possibility is simply to take compiler and try. Problem is that even if
it compiles and works, nobody is often able to say whether it is
standard compliant. Scary indeed....

Mirek

Mirek Fidler

unread,
Jul 28, 2003, 1:41:13 PM7/28/03
to
> Two-phase lookup helps address three problems:
>
> (a) Parsing templates in their generic form.

This is one I have mentioned. It is clearly good feature, but I am
far from convinced that the price paid (in complexity) outweights it. In
the end, it helps with correctness of libraries, but has no influence on
correctness of final binaries.

> (b) Accidental name capture.

Also nice, but not convincing. Similar problems still can happen and
most of them are unavoidable anyway. Programmers discipline and
responsibility is not amendable in this respect.

> (c) A template separation model.

Template separation model is a nice hypothesis, but I believe
completely unused in practice.

So the question is: What would we really loose by droping two-phase
lookup and adopting simple instatiation point lookup ? Other than those
completely weird and confusing statements like

this->baseMethod();

?

Mirek

Mirek Fidler

unread,
Jul 28, 2003, 3:07:46 PM7/28/03
to
> > Only benefit I can see so far is the possibility to detect some bugs
at
> > compile time, in case that concrete thing does not get instantiated,
but
> > such bugs seldom has any influence on code correctness.
>
> I have found that it has a tremendous impact on my coding cycle:
> Discovering a basic syntax error while I develop a template is far
> less frustrating than discovering it when I test the whole thing.

In fact, I found this very enjoyable too :)

> It enables separate compilation of templates. That in turn enables
> (but does not require) faster build times and non-source object
> file representations of templates.
>
> It also enables compiler implementations that represent templates
> in parsed form instead of as a token stream. The advantage of
> that is that template instantiation becomes a considerably cheaper
> (read: faster!) process. Some compilers do this today.

But I do not believe in real benefits of above two.

Simply said - I do not like this tradeoff :)

OTOH, two-phase lookup is here and unlikely to go away. Case is lost
:)

Mirek

Gabriel Dos Reis

unread,
Jul 28, 2003, 9:34:54 PM7/28/03
to
c...@volny.cz ("Mirek Fidler") writes:

| Simply said - I do not like this tradeoff :)

Then, you will find yourself frequently in trouble with C++ :-)

--
Gabriel Dos Reis, g...@integrable-solutions.net

---

Daveed Vandevoorde

unread,
Jul 29, 2003, 1:38:41 PM7/29/03
to
c...@volny.cz ("Mirek Fidler") wrote:
> > > Only benefit I can see so far is the possibility to detect some bugs
> at
> > > compile time, in case that concrete thing does not get instantiated,
> but
> > > such bugs seldom has any influence on code correctness.
> >
> > I have found that it has a tremendous impact on my coding cycle:
> > Discovering a basic syntax error while I develop a template is far
> > less frustrating than discovering it when I test the whole thing.
>
> In fact, I found this very enjoyable too :)
>
> > It enables separate compilation of templates. That in turn enables
> > (but does not require) faster build times and non-source object
> > file representations of templates.
> >
> > It also enables compiler implementations that represent templates
> > in parsed form instead of as a token stream. The advantage of
> > that is that template instantiation becomes a considerably cheaper
> > (read: faster!) process. Some compilers do this today.
>
> But I do not believe in real benefits of above two.

My impression is that Improved compilation speed is probably #1
on the list of active requests by various implementation teams.
(I suspect ABI stability ranks above that, but it's a less compromisable
feature ;-)

Not realizing that templates are not separated by default is probably
the #1 template FAQ.

Real enough to me.

> Simply said - I do not like this tradeoff :)

Fair enough.

> OTOH, two-phase lookup is here and unlikely to go away. Case is lost
> :)

I suspect so.

Daveed

ka...@gabi-soft.fr

unread,
Jul 29, 2003, 1:39:28 PM7/29/03
to
c...@volny.cz ("Mirek Fidler") wrote in message
news:<bfo7fe$h20os$1...@ID-198693.news.uni-berlin.de>...

> > Two-phase lookup helps address three problems:

> > (a) Parsing templates in their generic form.

> This is one I have mentioned. It is clearly good feature, but I am
> far from convinced that the price paid (in complexity) outweights
> it. In the end, it helps with correctness of libraries, but has no
> influence on correctness of final binaries.

Unless you are a provider of libraries:-).

My own early use of templates was in shops with a good software
development process. You didn't check code in until after it was
reviewed, and it passed all of the unit tests. (And the review process
included verifying the completeness of the tests.) And of course, at
the time, we only wrote simple templates; CFront didn't like it
otherwise:-).

The result is that I haven't ever found the fact that errors weren't
detected until link time a problem. Others apparently have different
experience (although what David said about libraries actually being
delivered with syntax errors scares me -- what kind of a process will
allow code to be delivered without it ever having been compiled).

> > (b) Accidental name capture.

> Also nice, but not convincing. Similar problems still can happen
> and most of them are unavoidable anyway. Programmers discipline and
> responsibility is not amendable in this respect.

I'm dubious about the value of this one, too. Either the project is
small, and there is no real problem, or it is large, and unless you have
some sort of naming discipline, you're going to have problems, even
without templates.

Until David's posting, this was the only argument I'd heard for two
phase name lookup, which is one of the reasons why I am extremely
dubious. It's a theoretical problem, but I can't really imagine it
being a problem in real life.

> > (c) A template separation model.

> Template separation model is a nice hypothesis, but I believe
> completely unused in practice.

It depends on what you mean by separation. We used to regularly put the
implementations in separate files, and only provide them at link time.
That much separation is absolutely essential in a large project. But
that much separation was already present in CFront (around 1990),
without two phase lookup.

How effective the separation was is an open question. I know that we
kept templates extremely simple in those days, to avoid problems. I
know that CFront had a very simplistic heuristic as to when it needed to
reinstantiate a template, and that if the build had strange,
inexplicable behavior, the first thing we did was clear out the
repository, and rebuild (so that CFront would regenerate all of the
instances again). And I know that CFront wasn't famous for its build
times, or rather, it was famous for them, but not in a positive way --
CFront recompiled a lot of your sources each time it instantiated.

Could these problems have been solved in the CFront model? Intuitively,
I thought so, but I've never actually tried to solve the problem. And
every one I know who has tried to solve it tells me that it isn't
solvable, or at least, that they don't know how to solve it. That may
not be many, but it includes some of the best (John Spicer, of EDG, and
Mike Ball, of Sun, in particular).

If David tells me that they need two phase lookup to implement export,
then I'll accept that as a very strong argument in favor of two phase
lookup. Because templates without some sort of separation are
pratically unusable in a large project. (On the other hand, as John
Spicer pointed out to me once, all of the early implementations: CFront,
g++ and even the earliest VC++, allowed some sort of superficial
separation.)

> So the question is: What would we really loose by droping
> two-phase lookup and adopting simple instatiation point lookup ?

Whatever the correct solution would have been in the past, we would
definitly loose by changing the rules one more time. I'm not happy with
some of the effects of two phase lookup. Big deal. I can and will live
with it. What I can't live with is the fact that every compiler
implements something different, because they are at different stages in
its adoption. And changing the rules now (or anytime in the future)
would make that situation even worse.

It's worth pointing out that all of the code I had that was broken by
two phase lookup triggered an error from the compiler. That the fix was
always fairly obvious (adding a this->, or something similar). And that
the fixed code still worked with the older compilers. Given that: I
can't say that I like it, but there are certainly worse things to worry
about. And I think that once all compilers implement it, correctly, it
will be much less of a problem; people may not always understand all of
the subtilities, but the can be taught what they have to do if the
compiler complains. After all, no one really understands all of the
rules for overload resolution, either, but we use it without any real
problems -- if the compiler complains, we add additional explicit typing
to shut it up. (Obviously, we write our code so that we don't care
which of the overloaded functions actually gets called. But hey, if the
functions do different things, they should have different names.)

--
James Kanze GABI Software mailto:ka...@gabi-soft.fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

---

ka...@gabi-soft.fr

unread,
Jul 29, 2003, 1:40:55 PM7/29/03
to
g...@integrable-solutions.net (Gabriel Dos Reis) wrote in message
news:<m3he5a7...@uniton.integrable-solutions.net>...
> ka...@gabi-soft.fr writes:

> [...]

> | I (like many other older programmers) am also bothered by the fact
> | that it breaks a lot of my existing code.

> That is interesting. In which ways does it break them?

Mainly by names meant to be dependant, that the compiler doesn't
consider dependant. Off hand, I'd guess that the most frequent case is
a template on a base class, and expecting to find certain things in the
base class. Something like:

template< typename T >
class X : public T
{
void f() { g() ; } // expect to find g in T...
} ;

> I would really like to understand how you wrote them and how trhey are
> now broken.

Try the above. It's a frequent idiom.

> I'm not implying you don't have such code, I'm just curious about the
> way you wrote them and the sort of assumptions you made. (I've
> already seen code not compiling any more with GCC-3.4, but I tend to
> think there were too many unspoken assumptions).

> | Again, breaking code should have been considered a high cost, and
> | should have weighed heavily against two phase lookup. But here
> | again, more early discussion would have helped.

> "more early" than 1992 would mean?

The first I heard about two phase lookup was when questions about broken
code started showing up in the newsgroups. I certainly didn't see any
published articles about it in 1992; I have seen very few to date, for
that matter.

> (The reference I gave is one of the oldest reference publically
> reachable, I would not be surprised that discussions related to that
> paper started even earlier, bringing us in 1991 or 1990, i.e. when
> committee works started).

Publically reachable doesn't mean that it was widely known and
available. Is it an article in C++ Reports? Or...

> | All of my template code was actually written after the first
> | discussions concerning two phase lookup in the standards working
> | group, and had I known that this was a possibility, I would have
> | (hopefully) written my code so that it worked both ways.

> Just curious: You mean, you never wrote any template code after early
> 1992?

I mean what I said, that all of my code was written *after* the issues
were being discussed in the committee. In fact, I didn't start using
templates until around 1995, and even then, only very carefully.

> Let's face it: templates were an experimental feature when proposed
> for standardization; as such it was expected that rules would change.

Let's face it: templates were just macros, and most people back then
expected them to more or less work like macros:-). (All of my initial
templates were straightforward conversions of code using generic.h. All
worked first go with both CFront and g++. Some don't work today.)

But you're right. I should have banned templates from production code
until they were stable. I just wonder when that will be.

Seriously, as usual, there is a cost/benefits trade-off. Using
"experimental" features (but C++ itself was experimental back then) is a
risk. In the case of templates, the gains are so high (compared to
generic.h, for example), that you take certain risks.

--
James Kanze GABI Software mailto:ka...@gabi-soft.fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

---

Daveed Vandevoorde

unread,
Jul 29, 2003, 1:42:11 PM7/29/03
to
g...@integrable-solutions.net (Gabriel Dos Reis) wrote:
> goo...@vandevoorde.com (Daveed Vandevoorde) writes:
>
> [...]
>
> | > Are there any
> | > any other *practical* benefits of two-phase lookup as opposed to single
> | > instantiation point lookup ? (as implemented in e.g. GCC)
> |
> | It enables separate compilation of templates.
>
> Maybe it would help if people remember that in 1992, the issue of
> separate or not separate compilation of templates was not on
> explicilty the table, because the separate compilation of template was
> implied as the default (mostly in the mind of the people who wrote the
> reference I gave).

Good point. Section 15.10 of "The Design and Evolution of C++"
(including the subsections) is also a good read: It presents two-
phase name lookup and implies a separation model.

(Written in 1993, I believe.)

Daveed

Mirek Fidler

unread,
Jul 29, 2003, 9:08:36 PM7/29/03
to
> My impression is that Improved compilation speed is probably #1
> on the list of active requests by various implementation teams.

Very likely. But precompiled headers are much more helpful in this
discipline.

Mirek

Gabriel Dos Reis

unread,
Jul 30, 2003, 10:24:54 AM7/30/03
to
c...@volny.cz ("Mirek Fidler") writes:

| > My impression is that Improved compilation speed is probably #1
| > on the list of active requests by various implementation teams.
|
| Very likely. But precompiled headers are much more helpful in this
| discipline.

Does that claim comes from actual comparison? If so, I would like to
understand why that is so.

>From what I've seen in some implementation, precompiled headers impose
other set of constraints.

--
Gabriel Dos Reis, g...@integrable-solutions.net

---

Jean-Marc Bourguet

unread,
Jul 30, 2003, 11:44:57 AM7/30/03
to
c...@volny.cz ("Mirek Fidler") writes:

> > My impression is that Improved compilation speed is probably #1
> > on the list of active requests by various implementation teams.
>
> Very likely. But precompiled headers are much more helpful in this
> discipline.

Precompiled headers are "much more helpful" than what?

David gave two sources of speed up:
* using parsed form instead of token stream in precompiled headers
* a good implementation of export

I assume that you are writing about the second point and I would like
to know what kind of measures you did? I experimented with export
using the Comeau's compiler and one of the thing I made was measuring
build time improvement. With Comeau's compiler, export is expected to
bring a build time improvement after a modification of the template
definition proportional to the number of compilation units using the
same instantiation (because only one of the compilation unit using a
given instanciation has to be recompiled instead of all). I first did
make into evidence the improvement using test case designed to do so.
After that I wrote a non artificial one to check if the improvement
was effective on non artificial cases (if you need 100 compilation
units using the same instantiation to see the improvement, this is not
effective). On that example recompiling after a template definition
modification with export and without precompiled headers is faster
than without export and with precompiled headers when there are *2*
compilation units using a template instanciation.

--
Jean-Marc

llewelly

unread,
Jul 30, 2003, 3:08:42 PM7/30/03
to
g...@integrable-solutions.net (Gabriel Dos Reis) writes:

> ka...@gabi-soft.fr writes:
>
> [...]
>
> | I (like many other older programmers) am also bothered by the fact that
> | it breaks a lot of my existing code.
>
> That is interesting. In which ways does it break them?
> I would really like to understand how you wrote them and how trhey are
> now broken. I'm not implying you don't have such code, I'm just
> curious about the way you wrote them and the sort of assumptions you
> made. (I've already seen code not compiling any more with GCC-3.4, but I
> tend to think there were too many unspoken assumptions).

In my experience, many programmers treat templates as a sort of macro
language. Most programmers don't attempt to read the standard, or
high quality books on the topic. If it compiles, they think it is
'right', and they move on. The most common unspoken assumption is that
the compilier does a simplistic token-oriented replacement. Is
this 'too many unspoken assumptions?' I'd have to say yes, since
it even leads to confusions with many traditional lookup
implementations. But IMO it is a pervasive assumption, and IMO any
compiler implementator not doing something about it is looking to
loose a lot of C++ users. (Unfortunately, probably the way to
loose the least users is to not implement two-phase lookup, or
maybe to be the last implementator to provide it.)

W.r.t. to gcc 3.4, or any other compiler switching from some older
lookup rules to two-phase lookup, I sincerely hope the
implementators:

(a) Preform two-phase lookup.
(b) Also preform the lookup done by older versions of the
compiler.

If (a) results in an error, but but (b) does not, emit an error
and use (b) to attempt to make the error comprehensible to a
naive programmer (who does not know of the existance of
two-phase lookup.)

If both (a) and (b) succeed, but result in different binding, bind
as per (a), but (by default) emit a warning (which of course
can be disabled by a specific flag.)

I'm afraid this won't be feasible for many of the implementators
changing to two-phase lookup. (In part because I don't really
believe the implementators of traditional lookup styles had a
precise documentation of *what* old lookup rules they were
implementing.) But if it doesn't happen, IMO another round of
minor disasters will strike large C++ projects everywhere.

It seems that for over 10 years (longer than I've been programming),
the phrase 'portability is seriously compromised by the fact that
existing C++ compilers implement wildy varying subsets of the
current draft standard' has been used to describe C++. Prior to
1998, I used that phrase a lot myself. After 1998, the 'draft'
part was no longer true, but remove that and the remainder
remained accurate.

In the past 2 years, I've come to hope that situation is finally a
thing of the past - I've even been telling people it's a thing of
the past. I think most other programmers are starting to belive
that problem is over or almost over. But now two-phase lookup
comes down the pike. Yes, I know, it was discussed long ago, and
has been in a few compilers for a few years now, but nonetheless
many will see it as 'oh, I guess there was another change to the
standard just now' simply because they haven't heard of it. I fear
it will be seen as proof that the phrase I quote above describes a
permanant situation, and not a temporary one.



>
> | Again, breaking code should have
> | been considered a high cost, and should have weighed heavily against two
> | phase lookup. But here again, more early discussion would have helped.
>
> "more early" than 1992 would mean?

D&E implies the discussion goes back before then. The real
problem is the C++ community rapidly became extrememely loose, and
large fractions of it have no direct contact with the standard,
and all too often, rely on books and documentation written by
people who never look at the standard. 'more early' doesn't mean
'earlier than 1992' that happened and IMO didn't help. 'more
early' must mean 'news spread to nearly every C++
programmer'. Unfortunately, it appears even then the C++
community didn't have the cohesion of e.g. the Java and Perl
communities.

IMO, the only solution to the confusion that comes from endless
differences between the various 'traditional' semantics, and the
standard semantics implementators are headed towards, is to have a
single source of news that nearly every C++ user pays attention
to. We don't have that. The closest we have are compiler
diagnostics. (No, IMO, compiler documentation does *not* count;
IIRC, gcc 2.95 docs clearly specified that treating 'std' as an
alias for the global namespace was a temporary situation, yet
years later gcc-help is still filled with questions from people
who wrote reams of code, much of it after 3.0 was released (but of
course using 2.9x), unknowingly relying on the aliasing of std to
the global namespace. (That's only the first example that comes to
mind, if I had a better memory, I bet I could point out similar
examples for every compiler I've used.))

> (The reference I gave is one of the oldest reference publically
> reachable, I would not be surprised that discussions related to that
> paper started even earlier, bringing us in 1991 or 1990, i.e. when
> committee works started).
>
> | All of my template code was actually written after the first discussions
> | concerning two phase lookup in the standards working group, and had I
> | known that this was a possibility, I would have (hopefully) written my
> | code so that it worked both ways.
>
> Just curious: You mean, you never wrote any template code after early
> 1992?

No - James said he *did* write template code after 1992, relying on
traditional lookup, ignorant of two-phase lookup. And he is not
alone, and he is not even the only expert C++ programmer who did
so.

> Let's face it: templates were an experimental feature when proposed
> for standardization; as such it was expected that rules would change.

'expected'? To people aware of the standard? Some of them. To most C++
programmers? Not by a million miles.

llewelly

unread,
Jul 30, 2003, 7:48:40 PM7/30/03
to
ka...@gabi-soft.fr writes:
[snip]

> The result is that I haven't ever found the fact that errors weren't
> detected until link time a problem. Others apparently have different
> experience (although what David said about libraries actually being
> delivered with syntax errors scares me -- what kind of a process will
> allow code to be delivered without it ever having been compiled).
[snip]

Maybe you miss the point. My interpretation of Daveed's post is the
code *was* compiled - just never with the template arguments
neccessary to trigger the syntax errors. (In a similar vein, I've
seen delivered code cotaining macros with syntax errors, which were
compiled, but never compiled in the conditions necessary to result
in the errors.)

Gabriel Dos Reis

unread,
Jul 30, 2003, 11:18:36 PM7/30/03
to
llewe...@xmission.dot.com (llewelly) writes:

| g...@integrable-solutions.net (Gabriel Dos Reis) writes:
|
| > ka...@gabi-soft.fr writes:
| >
| > [...]
| >
| > | I (like many other older programmers) am also bothered by the fact that
| > | it breaks a lot of my existing code.
| >
| > That is interesting. In which ways does it break them?
| > I would really like to understand how you wrote them and how trhey are
| > now broken. I'm not implying you don't have such code, I'm just
| > curious about the way you wrote them and the sort of assumptions you
| > made. (I've already seen code not compiling any more with GCC-3.4, but I
| > tend to think there were too many unspoken assumptions).
|
| In my experience, many programmers treat templates as a sort of macro
| language. Most programmers don't attempt to read the standard, or
| high quality books on the topic. If it compiles, they think it is
| 'right', and they move on.

I doubt James Kanze is that sort of programmer :-)

| The most common unspoken assumption is that
| the compilier does a simplistic token-oriented replacement. Is
| this 'too many unspoken assumptions?'

Yes. It is not that the issue of two-phase name lookup were invented
after 1995.

[...]

| W.r.t. to gcc 3.4, or any other compiler switching from some older
| lookup rules to two-phase lookup, I sincerely hope the
| implementators:
|
| (a) Preform two-phase lookup.
| (b) Also preform the lookup done by older versions of the
| compiler.

GCC-3.3 has already been warning for most "common" misconceptions with
additional note that those are "deprecated" -- meaning that future
versions will simply do two-phase name-lookup or be more stringent
about the infamous "typename".
It is just too complicated to accept codes written with bogus
assumptions. The GCC bug database contains examples where we've been
miscompiling a well-formed program according to the standard rules when in
the bogus mode.

[...]

| I'm afraid this won't be feasible for many of the implementators
| changing to two-phase lookup. (In part because I don't really
| believe the implementators of traditional lookup styles had a
| precise documentation of *what* old lookup rules they were
| implementing.)

Yes, part of the difficulty is to define what "old rules" means.
Another is the additional complexity -- which means more opportunities
to get many things wrong.

| It seems that for over 10 years (longer than I've been programming),
| the phrase 'portability is seriously compromised by the fact that
| existing C++ compilers implement wildy varying subsets of the
| current draft standard' has been used to describe C++. Prior to
| 1998, I used that phrase a lot myself. After 1998, the 'draft'

I do insist on the fact that 2-phase name lookup in templates is not
an invention made in 1998. Compiler implementors shipping their
products were aware of that aspect much much earlier than that.
Putting the change at 1998 leads to the kind of confused statement
that started this thread.

[...]

| > | Again, breaking code should have
| > | been considered a high cost, and should have weighed heavily against two
| > | phase lookup. But here again, more early discussion would have helped.
| >
| > "more early" than 1992 would mean?
|
| D&E implies the discussion goes back before then. The real
| problem is the C++ community rapidly became extrememely loose, and
| large fractions of it have no direct contact with the standard,
| and all too often, rely on books and documentation written by
| people who never look at the standard. 'more early' doesn't mean

Agreed in principle. But James Kanze is not the kind of person who
does not have a contact with the standard.

It is not that I'm willing to make this issue personal with respect
to James. From past discussions (either here or on the French
newsgroup fr.comp.lang.c++), he leaves me under the impression that
the committee decided to break his code he wrote around 1995 (date
given by himself) whereas he also claims to have had contact with the
standardization process (when I was in my enfancy :-). I have high
respect for his skills. But when he (well respected expert) writes
things like

> (The reference I gave is one of the oldest reference publically
> reachable, I would not be surprised that discussions related to that
> paper started even earlier, bringing us in 1991 or 1990, i.e. when
> committee works started).

Publically reachable doesn't mean that it was widely known and


available. Is it an article in C++ Reports? Or...

what better excuse for the confused programmer to continue to spread
confusions, like 2-phase name lookup being a last minute change?

I think experts have also the obligation to be fair and not help
spreading confusion. Being an expert does not mean being perfect.
Errare humanum est. However, there are sort of confusion they can
help to avoid.

[...]

| > (The reference I gave is one of the oldest reference publically
| > reachable, I would not be surprised that discussions related to that
| > paper started even earlier, bringing us in 1991 or 1990, i.e. when
| > committee works started).
| >
| > | All of my template code was actually written after the first discussions
| > | concerning two phase lookup in the standards working group, and had I
| > | known that this was a possibility, I would have (hopefully) written my
| > | code so that it worked both ways.
| >
| > Just curious: You mean, you never wrote any template code after early
| > 1992?
|
| No - James said he *did* write template code after 1992, relying on

Yes, there was a communication error between my mind and my fingers.
I'm sorry for the confusion.

--
Gabriel Dos Reis, g...@integrable-solutions.net

---

Daveed Vandevoorde

unread,
Jul 31, 2003, 2:01:24 PM7/31/03
to

Fair enough. D&E explained this at least as early as 1994.
The Usenet groups have been mentioning this since 1997.
See for example Bill Gibbons posting in this group:

http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&selm=bill-2607971020260001%40bgibbons.vip.best.com

> > | All of my template code was actually written after the first
> > | discussions concerning two phase lookup in the standards working
> > | group, and had I known that this was a possibility, I would have
> > | (hopefully) written my code so that it worked both ways.
>
> > Just curious: You mean, you never wrote any template code after early
> > 1992?
>
> I mean what I said, that all of my code was written *after* the issues
> were being discussed in the committee. In fact, I didn't start using
> templates until around 1995, and even then, only very carefully.

Note that the first publically available compiler to implement
two-phase
name lookup was HP's aC++ (for HP-UX): That was 1997. Your example
above has been triggering a warning (default mode) or error (strict
mode)
on that compiler for at least six years (and only about two years
after you
started using templates).

So, while it is unfortunate that this is only now getting implemented
more widely, it's hardly a "sudden" change. A long-time participant
in
either csc++ or clc++m (like yourself ;-) had a fair chance to prepare
for what was to come.

Daveed

Mirek Fidler

unread,
Aug 1, 2003, 1:46:06 AM8/1/03
to
> Yes, part of the difficulty is to define what "old rules" means.
> Another is the additional complexity -- which means more opportunities
> to get many things wrong.

I do not think it is so much difficult. For me, "old rules" simply
mean that all names are treated as dependent.

BTW, speaking about it, I do not see how non-dependent / dependent
resolution can help you in implementing "export" or checking template
before instantiation. As I can understand the issue, unavoidable
existence of dependent names in templates should mean that treating all
names as dependent would not change too much of compiler.....

Mirek

Daveed Vandevoorde

unread,
Aug 1, 2003, 12:17:19 PM8/1/03
to
c...@volny.cz ("Mirek Fidler") wrote:
[...]

> BTW, speaking about it, I do not see how non-dependent / dependent
> resolution can help you in implementing "export" or checking template
> before instantiation. As I can understand the issue, unavoidable
> existence of dependent names in templates should mean that treating all
> names as dependent would not change too much of compiler.....

Without phase 1, you cannot parse the template in generic form
unless you add much more disambiguation syntax (e.g., you'd
have to require something like "typename" even on a plain "T"
because you cannot look up "T" to establish it is a type). That
would be a much more drastic price to pay than 2-phase name
lookup.

Even if you were to enable parsing of generic templates somehow,
you'd no longer be able to access entities in the context of the
template definition since all lookups would happen in the context
of the template instantiation. So the following simple program
would be invalid:

// File 1:
void log() {}
export template<typename T> void et() {
log(); // Looked up in instantiation context with your model
}

// File 2:
export template<typename T> void et();
int main() {
et<void>(); // Error (in your model): log not found
}

Separate compilation of templates exacerbates the fact that there
are really (at least) two lookup contexts when dealing with templates.
You can come up with different ways to arrange the two lookup sets,
but I don't think you can make either lookup set (=phase) empty and
keep a viable model.

Daveed

Mirek Fidler

unread,
Aug 1, 2003, 2:16:05 PM8/1/03
to
> > BTW, speaking about it, I do not see how non-dependent /
dependent
> > resolution can help you in implementing "export" or checking
template
> > before instantiation. As I can understand the issue, unavoidable
> > existence of dependent names in templates should mean that treating
all
> > names as dependent would not change too much of compiler.....
>
> Without phase 1, you cannot parse the template in generic form
> unless you add much more disambiguation syntax (e.g., you'd
> have to require something like "typename" even on a plain "T"
> because you cannot look up "T" to establish it is a type). That
> would be a much more drastic price to pay than 2-phase name
> lookup.

Now I finally start to understand issue (I hope..) - you simply
would not be able to distinguish typenames for non-dependent names - and
that would lead to using "typename" for any type present in template (as
you must do for dependent names now...).

Thanks for explanation!

Mirek

James Kanze

unread,
Aug 10, 2003, 1:36:07 PM8/10/03
to
g...@integrable-solutions.net (Gabriel Dos Reis) writes:

|> llewe...@xmission.dot.com (llewelly) writes:

|> | g...@integrable-solutions.net (Gabriel Dos Reis) writes:

|> | > ka...@gabi-soft.fr writes:

|> | > [...]

|> | > | I (like many other older programmers) am also bothered by
|> | > | the fact that it breaks a lot of my existing code.

|> | > That is interesting. In which ways does it break them? I
|> | > would really like to understand how you wrote them and how
|> | > trhey are now broken. I'm not implying you don't have such
|> | > code, I'm just curious about the way you wrote them and the
|> | > sort of assumptions you made. (I've already seen code not
|> | > compiling any more with GCC-3.4, but I tend to think there
|> | > were too many unspoken assumptions).

|> | In my experience, many programmers treat templates as a sort of macro
|> | language. Most programmers don't attempt to read the standard, or
|> | high quality books on the topic. If it compiles, they think it is
|> | 'right', and they move on.

|> I doubt James Kanze is that sort of programmer :-)

I suspect that everyone is that sort of programmer, in certain
contexts. I am very much that sort of programmer for certain
things -- for example, I try export, and the compiler gives me an
error, so I conclude that I cannot use export, regardless of the
standard. (Not that that is really the point. I do use other means
of determining what is legal as well. Sometimes.)

In the end, writing standard conforming code isn't an end in itself.
It is, or should be, a means of improving portability. Regretfully,
for the moment, it is more a means of guaranteeing a lack of
portability. Which is, IMHO, a real problem -- perhaps the greatest
problem facing C++ at the moment. If all compilers actually
implemented two phase lookup in a standards conformant way, well,
whatever I felt about it, it would be a state of fact, and I'd live
with it. As would the people I work with, and anyone else using C++.
And where there might be problems with older code not compiling, at
least new code would either be correct, or not compile.

|> | The most common unspoken assumption is that the compilier
|> | does a simplistic token-oriented replacement. Is this 'too
|> | many unspoken assumptions?'

|> Yes. It is not that the issue of two-phase name lookup were
|> invented after 1995.

No. It's not as if all compilers implemented it as soon as it
appeared, either.

With regards to the "template is a macro", I don't know where the idea
got started (I've never seen that explination in any authorative
text), but it is widespread.

|> [...]

|> | W.r.t. to gcc 3.4, or any other compiler switching from some older
|> | lookup rules to two-phase lookup, I sincerely hope the
|> | implementators:

|> | (a) Preform two-phase lookup.
|> | (b) Also preform the lookup done by older versions of the
|> | compiler.

|> GCC-3.3 has already been warning for most "common" misconceptions
|> with additional note that those are "deprecated" -- meaning that
|> future versions will simply do two-phase name-lookup or be more
|> stringent about the infamous "typename".
|> It is just too complicated to accept codes written with bogus
|> assumptions.

I'm sorry, but if the code worked with earlier versions of the
compiler, it is not written with bogus assumptions.

Or is the bogus assumption that g++ supported templates before 3.3?
Maybe you're right. The real problem is that we've been rushing too
quickly to use templates. We really should ban them in production
code for another couple of years. Or... (Frankly, whatever the other
problems, I do not want to go back to <generic.h>.)

|> The GCC bug database contains examples where we've been
|> miscompiling a well-formed program according to the standard rules
|> when in the bogus mode.

|> [...]

|> | I'm afraid this won't be feasible for many of the implementators
|> | changing to two-phase lookup. (In part because I don't
|> | really believe the implementators of traditional lookup
|> | styles had a precise documentation of *what* old lookup
|> | rules they were implementing.)

|> Yes, part of the difficulty is to define what "old rules" means.
|> Another is the additional complexity -- which means more
|> opportunities to get many things wrong.

|> | It seems that for over 10 years (longer than I've been
|> | programming), the phrase 'portability is seriously
|> | compromised by the fact that existing C++ compilers
|> | implement wildy varying subsets of the current draft
|> | standard' has been used to describe C++. Prior to 1998, I
|> | used that phrase a lot myself. After 1998, the 'draft'

|> I do insist on the fact that 2-phase name lookup in templates is
|> not an invention made in 1998. Compiler implementors shipping
|> their products were aware of that aspect much much earlier than
|> that. Putting the change at 1998 leads to the kind of confused
|> statement that started this thread.

Yes and no. If I had been a compiler implementer, I wouldn't have
rushed to change my ARM conformant implementation of some feature to
match the latest drafts. Trying to track the changing drafts is a
sure recepe for frustration, both on the vendor side, and insofar as
you succeeded, on the user side.

Where templates are concerned, however, I think you have a real point.
Mainly because with the exception of CFront, the major implementations
did not appear until after the initial proposals for two stage lookup
in the committee (and I guess I should thank you for pointing this out
to me). I find it perfectly legitimate that a normal C++ user (the
role I try to play in standardization, because I feel that they are
somewhat underrepresented on the committee) is now being caught by
surprise. A normal C++ user does not follow the committee actions in
detail, and doesn't read the standard. For new features, he will
generally trust is compiler documentation. But implementors are NOT
normal users -- the year I really started using templates in
production code, I used Sun CC 4.2, g++ 2.6.something or
2.7.something, HP's CFront based CC, IBM's xlC and VC++ 5.0. All of
these implemented the classic CFront lookup, and as far as I can tell,
none of them even warned that this might only be a temporary solution
in their documentation.

So at least part of the blame can be placed on a certain number of
irresponsible implementors. Never the less, I didn't hear people in
the know screaming out that the implementors were being irresponsible
then, either. (OK, I'll admit that I don't know where they should
have been screaming in order to ensure that they were heard.)

|> [...]

|> | > | Again, breaking code should have been considered a high
|> | > | cost, and should have weighed heavily against two phase
|> | > | lookup. But here again, more early discussion would have
|> | > | helped.

|> | > "more early" than 1992 would mean?

|> | D&E implies the discussion goes back before then. The real
|> | problem is the C++ community rapidly became extrememely
|> | loose, and large fractions of it have no direct contact with
|> | the standard, and all too often, rely on books and
|> | documentation written by people who never look at the
|> | standard. 'more early' doesn't mean

|> Agreed in principle. But James Kanze is not the kind of person
|> who does not have a contact with the standard.

There is a great difference between not having contact with the
standard, and knowing everything that goes on in the standardization
effort. In the years 1993-94, I was fairly active in the
standardization effort, at the request of a customer, but most of my
effort was in the core issues -- I naïvely thought that once all of
the open core issues were resolved, the standard would be endorsed,
and my customer needed a standard, urgently. After that, my
involvement has been very much on a time available basis. Even an
aspect which personally interested me, such as iostream and
internationalization, I don't think I really realized that iostream
would be a template until CD2, although I'm sure the committee
considered it long before that.

|> It is not that I'm willing to make this issue personal with
|> respect to James. From past discussions (either here or on the
|> French newsgroup fr.comp.lang.c++), he leaves me under the
|> impression that the committee decided to break his code he wrote
|> around 1995 (date given by himself) whereas he also claims to have
|> had contact with the standardization process (when I was in my
|> enfancy :-). I have high respect for his skills. But when he
|> (well respected expert) writes things like

|> > (The reference I gave is one of the oldest reference
|> > publically reachable, I would not be surprised that
|> > discussions related to that paper started even earlier,
|> > bringing us in 1991 or 1990, i.e. when committee works
|> > started).

|> Publically reachable doesn't mean that it was widely known and
|> available. Is it an article in C++ Reports? Or...

|> what better excuse for the confused programmer to continue to
|> spread confusions, like 2-phase name lookup being a last minute
|> change?

Nobody is claiming it is a last minute change. Or that it wasn't
discussed in the standards committee. What is being claimed is that
it is surprising users, today, that it is breaking code, today, and
that most people don't seem to be aware of its existance.

And frankly, I'm not looking for a scapegoat -- I neither know nor
care if it is that the committee failed to adequately communicate, or
that implementors ignored this communication, or whatever. The fact
is that we now have a problem, and that we need a solution. Maybe
you've never used a compiler which didn't implement two phase lookup.
Maybe you've only read the standard, and used it as your sole source
of C++ knowledge. But you're not the only person out there, and a lot
of us were using C++ before the standard appeared, and learned it from
a variety of sources, including, to a great degree, trying things out
with various compilers. For us, 2-phase name lookup is a change that
hasn't fully occured yet.

|> I think experts have also the obligation to be fair and not help
|> spreading confusion. Being an expert does not mean being perfect.
|> Errare humanum est. However, there are sort of confusion they can
|> help to avoid.

You mean like pretending that the fact that something was discussed in
the committee makes it widespread knowledge.

Whatever the existing publications, all I can say is that I only
learned about 2-phase lookup in the last couple of years, thanks to
some responses to my questions in clc++m by David Vandevoorte.

Realistically, I fear that there have been two communities: those in
the know, and those like myself that didn't know that we weren't in
the know. The problem in such cases is that those in the know don't
generally realize how little those not in the know know; that we don't
even know enough to know that there are some questions we should be
asking.

With regards to the obligation of "experts", no one is an expert in
everything. With regards to templates, for example, I certainly
wouldn't qualify myself as an expert -- what little I know is thanks
to the patient explications of David Vandevoorde and John Spicer. But
there again, it is really only by accident that one of my questions
caused David to explain 2-phase lookup to me; I never asked any
questions about it, because I didn't even suspect its existance, and
in many earlier communications, neither he nor John mentiionned it,
doubtlessly because there simply supposed that I was aware of it, and
understood its implications. And I certainly hope that no one takes
my postings about templates as the Bible, because in this case, when I
say I am not an expert, it is definitly not false modesty, but a
simple statement of fact.

--
James Kanze mailto:ka...@gabi-soft.fr


Conseils en informatique orientée objet/

Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France +33 1 41 89 80 93

Gabriel Dos Reis

unread,
Aug 10, 2003, 4:33:42 PM8/10/03
to
ka...@gabi-soft.fr (James Kanze) writes:

| g...@integrable-solutions.net (Gabriel Dos Reis) writes:
|
| |> llewe...@xmission.dot.com (llewelly) writes:
|
| |> | g...@integrable-solutions.net (Gabriel Dos Reis) writes:
|
| |> | > ka...@gabi-soft.fr writes:
|
| |> | > [...]
|
| |> | > | I (like many other older programmers) am also bothered by
| |> | > | the fact that it breaks a lot of my existing code.
|
| |> | > That is interesting. In which ways does it break them? I
| |> | > would really like to understand how you wrote them and how
| |> | > trhey are now broken. I'm not implying you don't have such
| |> | > code, I'm just curious about the way you wrote them and the
| |> | > sort of assumptions you made. (I've already seen code not
| |> | > compiling any more with GCC-3.4, but I tend to think there
| |> | > were too many unspoken assumptions).
|
| |> | In my experience, many programmers treat templates as a sort of macro
| |> | language. Most programmers don't attempt to read the standard, or
| |> | high quality books on the topic. If it compiles, they think it is
| |> | 'right', and they move on.
|
| |> I doubt James Kanze is that sort of programmer :-)
|
| I suspect that everyone is that sort of programmer, in certain
| contexts.

Then, I must confess that I'm surprised that you don't attempt to read


high quality books on the topic.

| I am very much that sort of programmer for certain


| things -- for example, I try export, and the compiler gives me an
| error, so I conclude that I cannot use export, regardless of the
| standard.

This is quite different from

If it compiles, they think it is 'right', and they mode on.

I happen to teach programming to beginners who instinctively proceed
that way, but I also believe experts proceed differently, in industry.

| In the end, writing standard conforming code isn't an end in itself.

Completely agreed. That is why I'm surprised that as an experienced
programmer you didn't take the more conservative approach by putting
"this->" in front of expressions that are now problematic with more
conforming compilers. Doing that means it compiles with both
"broken" compilers and conformant ones. In doing that, back in 1995,
means you were putting yourself on the safe side: If the rules are
definitely adopted, then you're good. If the lenient behaviour was
retrofited in the standard, you are also good.

[...]

| |> | It seems that for over 10 years (longer than I've been
| |> | programming), the phrase 'portability is seriously
| |> | compromised by the fact that existing C++ compilers
| |> | implement wildy varying subsets of the current draft
| |> | standard' has been used to describe C++. Prior to 1998, I
| |> | used that phrase a lot myself. After 1998, the 'draft'
|
| |> I do insist on the fact that 2-phase name lookup in templates is
| |> not an invention made in 1998. Compiler implementors shipping
| |> their products were aware of that aspect much much earlier than
| |> that. Putting the change at 1998 leads to the kind of confused
| |> statement that started this thread.
|
| Yes and no. If I had been a compiler implementer, I wouldn't have
| rushed to change my ARM conformant implementation of some feature to
| match the latest drafts.

Sure, but that does not mean that the two phase name lookup was something
the committee did invent in 1998.

[...]

| Where templates are concerned, however, I think you have a real point.

And we are talking about templates.

[...]

| |> It is not that I'm willing to make this issue personal with
| |> respect to James. From past discussions (either here or on the
| |> French newsgroup fr.comp.lang.c++), he leaves me under the
| |> impression that the committee decided to break his code he wrote
| |> around 1995 (date given by himself) whereas he also claims to have
| |> had contact with the standardization process (when I was in my
| |> enfancy :-). I have high respect for his skills. But when he
| |> (well respected expert) writes things like
|
| |> > (The reference I gave is one of the oldest reference
| |> > publically reachable, I would not be surprised that
| |> > discussions related to that paper started even earlier,
| |> > bringing us in 1991 or 1990, i.e. when committee works
| |> > started).
|
| |> Publically reachable doesn't mean that it was widely known and
| |> available. Is it an article in C++ Reports? Or...
|
| |> what better excuse for the confused programmer to continue to
| |> spread confusions, like 2-phase name lookup being a last minute
| |> change?
|
| Nobody is claiming it is a last minute change.

then you should consult the message starting this sub-thread.

c...@volny.cz ("Mirek Fidler") writes:

# I think that most problems w.r.t. templates are due to the fact that
# as (perhaps) last minute change comitee decided that it would be a good
# idea to check templates even when they are not instantiated. And perhaps
# that it is bad that templates depened on order of declaration.

And yes, I note the "perhaps".

[...]

| |> I think experts have also the obligation to be fair and not help
| |> spreading confusion. Being an expert does not mean being perfect.
| |> Errare humanum est. However, there are sort of confusion they can
| |> help to avoid.
|
| You mean like pretending that the fact that something was discussed in
| the committee makes it widespread knowledge.

Not really.

[...]

| With regards to the obligation of "experts", no one is an expert in
| everything.

I certainly did not claim that someone is an expert in everything, and
I did not see anyone else saying so int this thread; so maybe you
might want to tell us what that has to do with the current discussion.

[...]

| And I certainly hope that no one takes
| my postings about templates as the Bible, because in this case, when I
| say I am not an expert, it is definitly not false modesty, but a
| simple statement of fact.

with no offense intended, I don't take your postings about template as
the Bible -- I have even come to exercise more skepticism :-)
However, I was objecting to your note about availability of
explanations on two-phase name lookup in templates.

--
Gabriel Dos Reis, g...@integrable-solutions.net

---

ka...@gabi-soft.fr

unread,
Aug 26, 2003, 10:19:40 AM8/26/03
to
g...@integrable-solutions.net (Gabriel Dos Reis) wrote in message
news:<m3znihx...@uniton.integrable-solutions.net>...
> ka...@gabi-soft.fr (James Kanze) writes:

> | g...@integrable-solutions.net (Gabriel Dos Reis) writes:

> | |> llewe...@xmission.dot.com (llewelly) writes:

> | |> | g...@integrable-solutions.net (Gabriel Dos Reis) writes:

> | |> | > ka...@gabi-soft.fr writes:

> | |> | > [...]

> | |> | > | I (like many other older programmers) am also bothered by
> | |> | > | the fact that it breaks a lot of my existing code.

> | |> | > That is interesting. In which ways does it break them? I
> | |> | > would really like to understand how you wrote them and how
> | |> | > trhey are now broken. I'm not implying you don't have such
> | |> | > code, I'm just curious about the way you wrote them and the
> | |> | > sort of assumptions you made. (I've already seen code not
> | |> | > compiling any more with GCC-3.4, but I tend to think there
> | |> | > were too many unspoken assumptions).

> | |> | In my experience, many programmers treat templates as a sort
> | |> | of macro language. Most programmers don't attempt to read
> | |> | the standard, or high quality books on the topic. If it
> | |> | compiles, they think it is 'right', and they move on.

> | |> I doubt James Kanze is that sort of programmer :-)

> | I suspect that everyone is that sort of programmer, in certain
> | contexts.

> Then, I must confess that I'm surprised that you don't attempt to read
> high quality books on the topic.

I don't read everything that is written about C++, that's for sure. I'd
never find the time. My "advanced" reading about templates was Barton
and Nackman -- they don't talk about two phase lookup. And of course,
having read Barton and Nackman, I knew more about templates than I could
use (given the quality of implementations at the time), so I didn't rush
out to learn even more. One can only read so much, and one must manage
priorities.

> | I am very much that sort of programmer for certain things -- for
> | example, I try export, and the compiler gives me an error, so I
> | conclude that I cannot use export, regardless of the standard.

> This is quite different from

> If it compiles, they think it is 'right', and they mode on.

> I happen to teach programming to beginners who instinctively proceed
> that way, but I also believe experts proceed differently, in industry.

There's a bit of wishful thinking in that:-).

No one is an expert in everything. And there are degrees of expertise.
Compared to others in this forum, I am far from being an expert in
templates; I do know them better than anyone else at my current and
previous customer sites, however. For the most part, companies
developing application software don't want (and shouldn't need)
"experts" in such a narrow domain -- in interviews, I typically get more
questions about UML than about templates, for example.

That doesn't mean, of course, that the local experts don't try to keep
abreast of developments. But for the most part, keeping abreast meant
scanning articles in C++ Reports and later CUJ, and not much more.

I might also add that for the most part, the local experts learned C++
some time ago, and became experts by doing, more than by reading. The
fact that even long after two phase lookup was adopted, NEW template
implementats (g++ or VC++, for example) ignored it, is certainly a major
cause of the problem.

> | In the end, writing standard conforming code isn't an end in itself.

> Completely agreed. That is why I'm surprised that as an experienced
> programmer you didn't take the more conservative approach by putting
> "this->" in front of expressions that are now problematic with more
> conforming compilers.

Even as an experienced programmer, I can only deal with problems I know
about. I first heard about two phased look-up a year or two ago, and it
is only very recently that I have become aware of the implementations.

Also, as I said, standard conforming code ISN'T the goal. The goal is
portable code. And for the moment, that pretty much means ignoring the
standard (which talks about things like two phase lookup and export,
which aren't present in the compilers I use), and considering what
compilers actually do.

I might add that I work in a team, and that I am concerned not only with
the code I write, but the code others write. And I've not seen such a
rule in any coding guidelines -- it certainly isn't present in the
Ellemtel guidelines. It doesn't do any good to say you have to write
code that way now; you (or someone) should have told me this ten years
ago.

> Doing that means it compiles with both "broken" compilers and
> conformant ones. In doing that, back in 1995, means you were putting
> yourself on the safe side: If the rules are definitely adopted, then
> you're good. If the lenient behaviour was retrofited in the standard,
> you are also good.

OK. Which coding guidelines should I have been using back in 1995?

For that matter, do you know of a set of coding guidelines for writing
portable templates today? Something that I can show to average
programmers, and expect them to follow, and not have problems.

Or is C++ supposed to be a language restricted to a small elite, and not
to be used by the common masses?

> [...]

> | |> | It seems that for over 10 years (longer than I've been
> | |> | programming), the phrase 'portability is seriously
> | |> | compromised by the fact that existing C++ compilers
> | |> | implement wildy varying subsets of the current draft
> | |> | standard' has been used to describe C++. Prior to 1998, I
> | |> | used that phrase a lot myself. After 1998, the 'draft'

> | |> I do insist on the fact that 2-phase name lookup in templates is
> | |> not an invention made in 1998. Compiler implementors shipping
> | |> their products were aware of that aspect much much earlier than
> | |> that. Putting the change at 1998 leads to the kind of confused
> | |> statement that started this thread.

> | Yes and no. If I had been a compiler implementer, I wouldn't have
> | rushed to change my ARM conformant implementation of some feature to
> | match the latest drafts.

> Sure, but that does not mean that the two phase name lookup was
> something the committee did invent in 1998.

Agreed. Before a similar discussion in fr.comp.lang.c++, I had sort of
supposed that it was something added near the end, mainly on the basis
of that being when I learned about it. Thanks to some of the messages
you posted, I realize that it was designed in from the beginning (of the
standardization, not of C++). Given that, I have no objection with the
committee "innovating": there was a definite mandate to added templates
to the language, and in 1990 (or thereabouts), the amount of existing
code using templates was pretty small, for obvious reasons.

If our goal is to find a guilty party (how do you say "bouc emmisaire"
in English?), then this is important, since it definitly exonerates the
committee. On the other hand, it doesn't change the fact that there is,
today, a problem. Or two: there is today a large body of code using
templates which doesn't take two phase lookup into account, and most
active C++ programmers (or at least, all those I have talked to at
customer sites) are totally unaware that such a thing exists. At the
very least, there has been a failure to communicate, somewhere along the
line.

And IMHO, the question shouldn't be who is to blame. Because where ever
the fault may lay, it won't change anything. The question is: where do
we go from here? How do we solve the two problems above? Just saying
that people could have (or should have) written their code differently
doesn't solve anything, because they didn't, and they still aren't.

> [...]

OK. I'll admit that I also thought it a "last minute change" for a
while.

Perhaps a more accurate statement would be that the question of whether
it is really a "last minute change"; it is experienced as such by the
majority of programmers, since compiler implementations (and most books
and articles) seem to have ignored it until the standard was actually
adopted.

> [...]

> | With regards to the obligation of "experts", no one is an expert in
> | everything.

> I certainly did not claim that someone is an expert in everything, and
> I did not see anyone else saying so int this thread; so maybe you
> might want to tell us what that has to do with the current discussion.

Well, you seem to be reproaching me for not knowing about the issue
earlier. All I'm saying is that I am not an expert in everything, and
that in fact, I am not an expert in templates.

At least not at the level practiced here. I do manage to write a number
of templates which work. At least in practice. What worries me is that
they may stop working once compilers start implementing the standard.
(Then again, they may continue working. In many ways, it is the fact
that I don't know which bothers me the most.)

--
James Kanze GABI Software mailto:ka...@gabi-soft.fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung


11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

---

0 new messages