Topic: Dependent names
Author: michael@mehlich.com (Michael Mehlich)
Date: Fri, 21 Oct 2005 05:14:32 GMT Raw View
Hello,
I'm trying to understand the notion of "dependent name" in C++
as defined by the ISO standard.
However, I could not derive the proper semantics for the following
program:
#include <iostream>
int foo(char) { std::cout << "char\n"; }
template<typename T> struct X {
int bar(unsigned int) { };
int baz() {
foo(bar(0));
};
};
int foo(int) { std::cout << "int\n"; }
int main() {
X<int> x;
x.baz();
};
Section 14.6.2., paragraph 1 of the standard suggests
strongly that the use of bar in the member function baz
does not denote a dependent name.
On the other hand, section 14.6.2.2, paragraph 3 could
suggest that bar is an identifier that is declared with
a dependent type (if one considers the type of the implicit
object parameter X<T>& as a participant in bar's type).
As such, bar seems to be a non-dependent name that is a type
dependent expression...
The three C++ compilers I have access to all consider bar(0)
as a type-dependent expression, resulting in the use of foo
in the member function baz being a dependent name.
This is the case even if bar is declared to be a static
member function.
Is this behavior correct?
How do I derive the answer from the standard?
If I change the class template X to
template<typename T> struct X {
int bar(unsigned int) { };
int bar(T) { };
int baz() {
foo(bar(0));
};
};
the above-mentioned compilers will resolve bar in baz
to call the member function int bar(T).
Thus, bar seems to be considered to be a dependent name, thus
violating 14.6.2., paragraph 1.
However, if bar in baz is not a dependent name, then it must
be bound during template definition, requiring that int bar(T)
is ignored (as dependent on the template parameter), and therefore
bar in baz is bound to int bar(unsigned int)...
Puzzled,
Michael
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: anthony_w.geo@yahoo.com (Anthony Williams)
Date: Fri, 21 Oct 2005 14:47:15 GMT Raw View
michael@mehlich.com (Michael Mehlich) writes:
> #include <iostream>
>
> int foo(char) { std::cout << "char\n"; }
>
> template<typename T> struct X {
> int bar(unsigned int) { };
> int baz() {
> foo(bar(0));
> };
> };
>
> int foo(int) { std::cout << "int\n"; }
>
> int main() {
> X<int> x;
> x.baz();
> };
> Section 14.6.2., paragraph 1 of the standard suggests
> strongly that the use of bar in the member function baz
> does not denote a dependent name.
Correct. bar is an unqualified name, and the parameter supplied is not
type-dependent, so bar is not a dependent name. bar is therefore looked up in
the context of the definition of X, and resolves to the member function
X::bar, as the only bar in scope.
> On the other hand, section 14.6.2.2, paragraph 3 could
> suggest that bar is an identifier that is declared with
> a dependent type (if one considers the type of the implicit
> object parameter X<T>& as a participant in bar's type).
This use of bar has been resolved to X<T>::bar, so is a type-dependent
expression, yes.
> As such, bar seems to be a non-dependent name that is a type
> dependent expression...
Correct.
> The three C++ compilers I have access to all consider bar(0)
> as a type-dependent expression, resulting in the use of foo
> in the member function baz being a dependent name.
> This is the case even if bar is declared to be a static
> member function.
> Is this behavior correct?
Yes.
> How do I derive the answer from the standard?
>
> If I change the class template X to
> template<typename T> struct X {
> int bar(unsigned int) { };
> int bar(T) { };
> int baz() {
> foo(bar(0));
> };
> };
> the above-mentioned compilers will resolve bar in baz
> to call the member function int bar(T).
> Thus, bar seems to be considered to be a dependent name, thus
> violating 14.6.2., paragraph 1.
No. bar is still a non-dependent name; however in this case, the overload
resolution cannot be done until the full signature of bar(T) has been
identified at template instantiation time, so it is bound to the declarations
bar(unsigned int) and bar(T).
Anthony
--
Anthony Williams
Software Developer
Just Software Solutions Ltd
http://www.justsoftwaresolutions.co.uk
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: dave@boost-consulting.com (David Abrahams)
Date: Fri, 21 Oct 2005 14:49:08 GMT Raw View
michael@mehlich.com (Michael Mehlich) writes:
> Hello,
>
> I'm trying to understand the notion of "dependent name" in C++
> as defined by the ISO standard.
> However, I could not derive the proper semantics for the following
> program:
>
> #include <iostream>
>
> int foo(char) { std::cout << "char\n"; }
>
> template<typename T> struct X {
> int bar(unsigned int) { };
> int baz() {
> foo(bar(0));
> };
> };
>
> int foo(int) { std::cout << "int\n"; }
>
> int main() {
> X<int> x;
> x.baz();
> };
It's ill-formed :)
At the very least, you need to get rid of the final semicolon.
And then there's the issue of the missing return statements...
> Section 14.6.2., paragraph 1 of the standard suggests
> strongly that the use of bar in the member function baz
> does not denote a dependent name.
Correct.
> On the other hand, section 14.6.2.2, paragraph 3 could
> suggest that bar is an identifier that is declared with
> a dependent type (if one considers the type of the implicit
> object parameter X<T>& as a participant in bar's type).
That seems like unfortunately vague wording.
> As such, bar seems to be a non-dependent name that is a type
> dependent expression...
>
> The three C++ compilers I have access to all consider bar(0)
> as a type-dependent expression
I believe you have access to http://www.comeaucomputing.com/tryitout/.
Try compiling the following with that compiler; I hope you will find
it helpful:
#include <iostream>
void foo(char) { std::cout << "char\n"; }
template<typename T> struct X {
int bar(unsigned int) { return 0; };
int baz() {
return foo(bar(0));
};
};
int foo(int) { std::cout << "int\n"; return 0; }
> resulting in the use of foo in the member function baz being a
> dependent name. This is the case even if bar is declared to be a
> static member function.
>
> Is this behavior correct?
No.
> How do I derive the answer from the standard?
AFAICT, the only way is to understand the type of a non-dependent name
that denotes a (member) function to be its return type.
I think this is a wording problem in the standard that should be
fixed.
--
Dave Abrahams
Boost Consulting
www.boost-consulting.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: hyrosen@mail.com (Hyman Rosen)
Date: Fri, 21 Oct 2005 14:49:27 GMT Raw View
Michael Mehlich wrote:
> template<typename T> struct X {
> int bar(unsigned int) { };
> int baz() {
> foo(bar(0));
> };
> };
The key to understanding this is in 9.3.1/2, which is
hard to find because it's not about templates. That
paragraph says
When an id-expression ... is used in the body of a
nonstatic member function of class X ... if name lookup
... resolves the name in the id-expression to a nonstatic
nontype member of class X ..., the id-expression is
transformed into a class member access expression ...
using (*this)...
So the definition of baz transforms into
int baz() { foo((*this).bar(0)); }
becuase bar is found in the way 9.3.1/2 specifies. Now the
argument of foo is seen to be dependent because 'this' is
dependent by 14.6.2.2/2 (its type is X<T>*). So foo itself
becomes a dependent name. Very tricky and counterintuitive.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: google@vandevoorde.com
Date: Sat, 22 Oct 2005 23:49:46 CST Raw View
Michael Mehlich wrote:
> Hello,
>
> I'm trying to understand the notion of "dependent name" in C++
> as defined by the ISO standard.
> However, I could not derive the proper semantics for the following
> program:
>
> #include <iostream>
>
> int foo(char) { std::cout << "char\n"; }
>
> template<typename T> struct X {
> int bar(unsigned int) { };
> int baz() {
> foo(bar(0));
> };
> };
>
> int foo(int) { std::cout << "int\n"; }
>
> int main() {
> X<int> x;
> x.baz();
> };
>
> Section 14.6.2., paragraph 1 of the standard suggests
> strongly that the use of bar in the member function baz
> does not denote a dependent name.
Indeed.
> On the other hand, section 14.6.2.2, paragraph 3 could
> suggest that bar is an identifier that is declared with
> a dependent type (if one considers the type of the implicit
> object parameter X<T>& as a participant in bar's type).
No, inside the definition of X<T>, X<T> itself is not considered
template dependent. (This notion has been made considerably
clearer in the current working paper. Specifically, 14.6.4.1 has
been rewritten.)
> As such, bar seems to be a non-dependent name that is a type
> dependent expression...
See above, it's plainly nondependent. But...
> The three C++ compilers I have access to all consider bar(0)
> as a type-dependent expression, resulting in the use of foo
> in the member function baz being a dependent name.
> This is the case even if bar is declared to be a static
> member function.
>
> Is this behavior correct?
Certainly not. Even if you could somehow conclude that
in "foo(bar(0))" the "foo" is subject to a lookup at the
point of instantiation (the so-called "phase-2 lookup),
that lookup is only an "argument-dependent lookup"
(ADL). In this case, the type of bar(0) at the point of
instantiation is "int", which has no associated namespaces
and therefore ADL adds nothing in phase 2. So you'd
still end up calling only a candidate found in phase 1
using ordinary lookup (OL): In this case foo(char) is the
only such candidate.
Most compilers get this completely wrong: They do all
lookups (OL and ADL) for names that appear in function
template definitions at the point of instantiation. (That
because they don't even parse those templates in generic
form -- mostly for historical reasons.) Among the few
that do some lookup in phase 1, most seem to still do
something not quite right with the OL/ADL split.
(But as explained above, the call to foo and bar are both
nondependent, and therefore both OL and ADL must be
done in phase 1 in this example.)
> How do I derive the answer from the standard?
See above. A current copy of the working paper is
probably needed to pick up all the recent clarifications
in this area.
> If I change the class template X to
> template<typename T> struct X {
> int bar(unsigned int) { };
> int bar(T) { };
> int baz() {
> foo(bar(0));
> };
> };
> the above-mentioned compilers will resolve bar in baz
> to call the member function int bar(T).
> Thus, bar seems to be considered to be a dependent name, thus
> violating 14.6.2., paragraph 1.
>
> However, if bar in baz is not a dependent name, then it must
> be bound during template definition, requiring that int bar(T)
> is ignored (as dependent on the template parameter), and therefore
> bar in baz is bound to int bar(unsigned int)...
bar in bar(0) is indeed nondependent, and so subject to the
rules of 14.6.3. However, that doesn't preclude it from finding
both bar(T) and bar(unsigned), so that eventually bar<int>(int)
is selected for the call.
Can you elaborate on why you think bar(T) might need to be
ignored?
Anyway, I hope the above somewhat clarifies things.
Daveed
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: pongba@gmail.com
Date: Mon, 24 Oct 2005 20:52:13 CST Raw View
but comeau emits an error.
"ComeauTest.c", line 8: error: more than one instance of overloaded
function
"X<T>::bar" matches the argument list, the choices that match
are:
function "X<T>::bar(unsigned int)"
function "X<T>::bar(T)"
The argument types that you used are: (int)
foo(bar(0));
IMO, the real question is, what does the 'bound' in 14.6.3 mean?
Does it mean an overload resolution? If it is, here the resolution
really can't be done because bar(T) is
essentially not a function template so that it's 'T' couldn't be
deduced. But comeau compiler seems not want to kick it out
of the candidate set,but emit an error instead.
Does there exists any statement in the standard that makes this clear?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: google@vandevoorde.com
Date: 25 Oct 2005 22:50:12 GMT Raw View
pongba@gmail.com wrote:
> but comeau emits an error.
>
> "ComeauTest.c", line 8: error: more than one instance of overloaded
> function
> "X<T>::bar" matches the argument list, the choices that match
> are:
> function "X<T>::bar(unsigned int)"
> function "X<T>::bar(T)"
> The argument types that you used are: (int)
> foo(bar(0));
I believe that's an EDG bug, unfortunately. I've entered a defect
report
for it.
> IMO, the real question is, what does the 'bound' in 14.6.3 mean?
It means that the set of entities referred to by the name is fully
determined.
> Does it mean an overload resolution?
No.
> If it is, here the resolution
> really can't be done because bar(T) is
> essentially not a function template so that it's 'T' couldn't be
> deduced.
That's right.
> But comeau compiler seems not want to kick it out
> of the candidate set,but emit an error instead.
>
> Does there exists any statement in the standard that makes this clear?
There does appear to be a problem with the standard wording in
this case. I've submitted a core issue to address it. One possible
interpretation is what while "bar" is a nondependent name by
14.6.2/1 (so it is bound in phase 1), it is a type-dependent
expression by 14.6.2.2/3 (with a change required to deal with
overload sets). (All references into the current WP.) I don't
particularly like that answer, but it seems viable.
Daveed
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: hyrosen@mail.com (Hyman Rosen)
Date: Thu, 27 Oct 2005 00:19:26 GMT Raw View
google@vandevoorde.com wrote:
> I believe that's an EDG bug, unfortunately. I've entered a defect
> report for it.
Did you see my comment about 9.3.1/2? Do you disagree that
this is what causes the name to be dependent?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: google@vandevoorde.com
Date: Fri, 28 Oct 2005 10:51:33 CST Raw View
Hyman Rosen wrote:
> google@vandevoorde.com wrote:
> > I believe that's an EDG bug, unfortunately. I've entered a defect
> > report for it.
>
> Did you see my comment about 9.3.1/2? Do you disagree that
> this is what causes the name to be dependent?
I did read. Sorry for not responding.
Unfortunately, no, that does no apply because that happens _after_
full binding (when you know that you are dealing with a nonstatic
member function), whereas whether a name is dependent or not
must be determined earlier (hence the rules are mostly syntactic
or at most based on phase-1 lookup only).
Daveed
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: hyrosen@mail.com (Hyman Rosen)
Date: Fri, 28 Oct 2005 17:30:55 GMT Raw View
google@vandevoorde.com wrote:
> Hyman Rosen wrote:
>>Did you see my comment about 9.3.1/2? Do you disagree that
>>this is what causes the name to be dependent?
>
> Unfortunately, no, that does no apply because that happens _after_
> full binding (when you know that you are dealing with a nonstatic
> member function), whereas whether a name is dependent or not
> must be determined earlier (hence the rules are mostly syntactic
> or at most based on phase-1 lookup only).
I'm not so sure you're right. Let me quote 9.3.1/2 for reference:
When an id-expression ... is used in the body of a nonstatic
member function of class X ..., if name lookup (3.4.1) resolves
the name in the id-expression to a nonstatic nontype member of
class X or of a base class of X, the id-expression is transformed
into a class member access expression (5.2.5) using (*this) (9.3.2)
as the postfix-expression to the left of the . operator. ...
Similarly during name lookup, when an unqualified-id (5.1) used in
the definition of a member function for class X resolves to a static
member ... of class X ..., the unqualified-id is transformed into a
qualified-id (5.1) in which the nested-name-specifier names the class
of the member function.
Notice that phrase "Similarly during name lookup". That strongly implies
that both transformations, nonstatic and static, take place when the name
is looked up. Now, with 14.6.2/1 saying
In an expression of the form:
postfix-expression ( expression-listopt )
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 expression-list must be examined first, and therefore the transformation
using 'this' will have already happened, causing the function name to become
dependent.
Now, maybe 9.3.1/2 should not be interpreted that way, but why not?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: google@vandevoorde.com
Date: Sun, 30 Oct 2005 11:34:17 CST Raw View
Hyman Rosen wrote:
> google@vandevoorde.com wrote:
> > Hyman Rosen wrote:
> >>Did you see my comment about 9.3.1/2? Do you disagree that
> >>this is what causes the name to be dependent?
> >
> > Unfortunately, no, that does no apply because that happens _after_
> > full binding (when you know that you are dealing with a nonstatic
> > member function), whereas whether a name is dependent or not
> > must be determined earlier (hence the rules are mostly syntactic
> > or at most based on phase-1 lookup only).
>
> I'm not so sure you're right. Let me quote 9.3.1/2 for reference:
> When an id-expression ... is used in the body of a nonstatic
> member function of class X ..., if name lookup (3.4.1) resolves
> the name in the id-expression to a nonstatic nontype member of
> class X or of a base class of X, the id-expression is transformed
> into a class member access expression (5.2.5) using (*this) (9.3.2)
> as the postfix-expression to the left of the . operator. ...
> Similarly during name lookup, when an unqualified-id (5.1) used in
> the definition of a member function for class X resolves to a static
> member ... of class X ..., the unqualified-id is transformed into a
> qualified-id (5.1) in which the nested-name-specifier names the class
> of the member function.
Note that this means that "f()" is transformed into something like
"(*this).f()" or "C::f()" (but not for example "f(*this)"). I.e.,
after
this transformation, the call is no longer of the form
identifier (expression-list_opt)
So the following would no longer apply:
> Notice that phrase "Similarly during name lookup". That strongly implies
> that both transformations, nonstatic and static, take place when the name
> is looked up. Now, with 14.6.2/1 saying
> In an expression of the form:
> postfix-expression ( expression-listopt )
> 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 expression-list must be examined first, and therefore the transformation
> using 'this' will have already happened, causing the function name to become
> dependent.
9.3.1/2 is not a token transformation. I.e., it's not meant to say
that a certain token sequence should be reparsed as another and
then conclusions drawn from that. Instead, it's meant to be a
semantic equivalence transformation to determine the meaning
of a call. For a given call "f()", the transformation may have to be
done (in principle) several times for each member of an overload
set (and it may be different for the different members if some are
static and others are nonstatic). The semantic consequences of
the transformation can then affect overload resolution.
(Now that I think of it, I wonder if 9.3.1/2 might have a defect
wrt. access violations when combined with using declarations?)
The core of much 14.6.2/1 on the other hand is mainly a syntactic
rule: "If you see token sequence with such and such properties,
then do lookup first this way".
I do agree with you that the words "Similarly, during name lookup..."
suggest that the transformation happens so early as to be equivalent
to a token rewrite. Maybe that deserves a core issue. I'll look into
it.
Thanks,
Daveed
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: google@vandevoorde.com
Date: Sun, 30 Oct 2005 11:34:09 CST Raw View
Forget that bit about the access violation issues. I misread the
meaning of
"the class of the member function" in that paragraph of 9.3.1.
Daveed
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: hyrosen@mail.com (Hyman Rosen)
Date: Mon, 31 Oct 2005 14:45:25 GMT Raw View
google@vandevoorde.com wrote:
> Note that this means that "f()" is transformed into something like
> "(*this).f()" or "C::f()" (but not for example "f(*this)"). I.e.,
> after this transformation, the call is no longer of the form
> identifier (expression-list_opt)
> So the following would no longer apply:
I think you're forgetting the OP's example:
#include <iostream>
int foo(char) { std::cout << "char\n"; }
template<typename T> struct X {
int bar(unsigned int) { };
int baz() { foo(bar(0)); };
};
int foo(int) { std::cout << "int\n"; }
int main() { X<int> x; x.baz(); };
It's the 'bar' in the 'foo(bar(0))' expression which becomes
foo((*this).bar(0))
because name lookup on 'bar' finds a nonstatic member name.
Then this affects whether 'foo' is a dependent name, because
that call is still in the proper form.
Now, I believe it is indisputable that if the code is actually
*written* as 'foo((*this).bar(0))' then 'foo' is a dependent name,
because of 14.6.2.2/2. In that case, it seems to me that it would
be very confusing to treat 'foo(bar(0))' differently, given that
this expression means the same thing as the other one.
I think the way out of this problem is to augment the set of things
in 14.6.2.2/3 which are not type-dependent to include calls to member
functions, whether static or nonstatic and whether they use (*this).f()
this->f(), or plain f(), unless the return type is type-dependent. If
we did this, then in both 'foo(bar(0))' and 'foo((*this).bar(0))' we
would find 'foo' not to be type-dependent, and foo(char) would be
called in all cases, which is the only thing that really makes sense.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: google@vandevoorde.com
Date: Wed, 2 Nov 2005 09:51:16 CST Raw View
Hyman Rosen wrote:
> google@vandevoorde.com wrote:
> > Note that this means that "f()" is transformed into something like
> > "(*this).f()" or "C::f()" (but not for example "f(*this)"). I.e.,
> > after this transformation, the call is no longer of the form
> > identifier (expression-list_opt)
> > So the following would no longer apply:
>
> I think you're forgetting the OP's example:
> #include <iostream>
> int foo(char) { std::cout << "char\n"; }
> template<typename T> struct X {
> int bar(unsigned int) { };
> int baz() { foo(bar(0)); };
> };
> int foo(int) { std::cout << "int\n"; }
> int main() { X<int> x; x.baz(); };
>
> It's the 'bar' in the 'foo(bar(0))' expression which becomes
> foo((*this).bar(0))
> because name lookup on 'bar' finds a nonstatic member name.
> Then this affects whether 'foo' is a dependent name, because
> that call is still in the proper form.
I think you're right that I might have lost track of the actual
question. However, it doesn't really make a difference: In
that example for foo and bar are nondependent in the call
to "foo(bar(0))".
As I mentioned in my earliest post, it doesn't actually matter
for the outcome of the call in this example, what the name
dependence is, because no ADL is involved. The following
variation is more interesting:
struct S {};
int foo(char);
template<typename T> struct X {
S* bar(unsigned int) { return 0; };
void baz() { foo(bar(0)); };
};
int foo(S);
int main() { X<int> x; x.baz(); };
This example would be valid if bar(0) were dependent,
but as things stand now, it is invalid.
> Now, I believe it is indisputable that if the code is actually
> *written* as 'foo((*this).bar(0))' then 'foo' is a dependent name,
> because of 14.6.2.2/2.
Agreed.
> In that case, it seems to me that it would
> be very confusing to treat 'foo(bar(0))' differently, given that
> this expression means the same thing as the other one.
I think it's confusing either way ;-)
The current rules have the advantage that you don't need to
know whether the called function is a member or not to
decide it's a nondependent name.
> I think the way out of this problem is to augment the set of things
> in 14.6.2.2/3 which are not type-dependent to include calls to member
> functions, whether static or nonstatic and whether they use (*this).f()
> this->f(), or plain f(), unless the return type is type-dependent. If
> we did this, then in both 'foo(bar(0))' and 'foo((*this).bar(0))' we
> would find 'foo' not to be type-dependent, and foo(char) would be
> called in all cases, which is the only thing that really makes sense.
The wording changes that introduced the notion of "current
instantiation" (14.6.2.1) make a small step in that direction in
the sense that for a proper member m of X<T> both "m" and
"X<T>::m" are considered nondependent inside the definition
of X<T>. I think the changes shied away from involving
expression-based qualification constructs (this-> etc.) because
the spectrum of variations is too dense (this->m, (&(*this))->m,
etc.).
Daveed
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: James.Kanze@dresdner-bank.com
Date: 1999/07/26 Raw View
In article <7m4tp9$act$1@nnrp1.deja.com>,
wmm@fastdial.net wrote:
> In article <070719991258361828%lisa_lippincott@advisories.com>,
> Lisa Lippincott <lisa_lippincott@advisories.com> wrote:
> >
> >
> > Consider this template:
> >
> > template < class T > void F( void (*p)(T) = X ) {...}
> >
> > Is X a dependent name?
> >
> > I think it should be -- in non-template code, the referent of X
would
> > vary with the type T. But I can't show from the standard that X is
> > dependent. In particular, there's nothing in 14.6.2.2
[temp.dep.expr]
> > that says that X is dependent.
>
> Even if X were dependent, it wouldn't do you any good. The only
> extra lookup that is done for dependent names is a Koenig lookup
> (argument-dependent lookup, 3.4.2) in namespaces from the
> instantiation context (14.6.4); you don't get a normal lookup
> there. Since the address of a function has no arguments, there is
> no argument-dependent lookup and you would still find only the
> Xs that were visible in the definition context, even if X were
> dependent.
I think her point is the opposite: if X isn't dependant, it will do her
harm. Non-dependant names are bound at the point of template
definition, and if I understand her correctly, at the point of template
definition, there are no X's, or at least, there are no functions X that
correspond to the desired X.
There may be no extra lookup for dependant names, but the lookup that
there is occurs at a different place.
--
James Kanze mailto:
James.Kanze@dresdner-bank.com
Conseils en informatique orientie objet/
Beratung in objekt orientierter
Datenverarbeitung
Ziegelh|ttenweg 17a, 60598 Frankfurt, Germany Tel. +49 (069) 63 19 86
27
Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: wmm@fastdial.net
Date: 1999/07/27 Raw View
In article <7mfqkv$ntd$1@nnrp1.deja.com>,
James.Kanze@dresdner-bank.com wrote:
> In article <7m4tp9$act$1@nnrp1.deja.com>,
> wmm@fastdial.net wrote:
> > In article <070719991258361828%lisa_lippincott@advisories.com>,
> > Lisa Lippincott <lisa_lippincott@advisories.com> wrote:
> > >
> > >
> > > Consider this template:
> > >
> > > template < class T > void F( void (*p)(T) = X ) {...}
> > >
> > > Is X a dependent name?
> > >
> > > I think it should be -- in non-template code, the referent of X
> would
> > > vary with the type T. But I can't show from the standard that X
is
> > > dependent. In particular, there's nothing in 14.6.2.2
> [temp.dep.expr]
> > > that says that X is dependent.
> >
> > Even if X were dependent, it wouldn't do you any good. The only
> > extra lookup that is done for dependent names is a Koenig lookup
> > (argument-dependent lookup, 3.4.2) in namespaces from the
> > instantiation context (14.6.4); you don't get a normal lookup
> > there. Since the address of a function has no arguments, there is
> > no argument-dependent lookup and you would still find only the
> > Xs that were visible in the definition context, even if X were
> > dependent.
>
> I think her point is the opposite: if X isn't dependant, it will do
her
> harm. Non-dependant names are bound at the point of template
> definition, and if I understand her correctly, at the point of
template
> definition, there are no X's, or at least, there are no functions X
that
> correspond to the desired X.
>
> There may be no extra lookup for dependant names, but the lookup that
> there is occurs at a different place.
No, for both dependent and non-dependent names, the only normal
(non-Koenig) lookup that is done is from the context of the
template definition. The only thing that is different for a
dependent name is that the Koenig portion of the lookup includes
namespaces that are visible in the instantiation context as well
as those visible in the definition context. (See 14.6.4.)
--
William M. Miller, wmm@fastdial.net
Software Emancipation Technology (www.setech.com)
Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Lisa Lippincott <lisa_lippincott@advisories.com>
Date: 1999/07/27 Raw View
James Kanze <James.Kanze@dresdner-bank.com> wrote, referring to me:
> I think her point is the opposite: if X isn't dependant, it will do
> her harm. Non-dependant names are bound at the point of template
> definition...
William M. Miller <wmm@fastdial.net> wrote:
> No, for both dependent and non-dependent names, the only normal
> (non-Koenig) lookup that is done is from the context of the
> template definition. The only thing that is different for a
> dependent name is that the Koenig portion of the lookup includes
> namespaces that are visible in the instantiation context as well
> as those visible in the definition context. (See 14.6.4.)
Looking closer, I see that you're both right. The basic trouble I have
is that while I can write something like:
template <class T> void Print( const T& t ) { std::cout << t; }
I have no way of taking the address of the operator<< that this
function uses. To get that address, I would have to form a dependent
name for operator<<, and contrive to have Koenig lookup apply to that
name. Neither seems possible when taking the address of a function.
--Lisa Lippincott
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: AllanW <allan_w@my-deja.com>
Date: 1999/07/15 Raw View
Lisa Lippincott <lisa_lippincott@advisories.com> writes:
> >Consider this template:
>
> >template < class T > void F( void (*p)(T) = X ) {...}
>
> >Is X a dependent name?
In article <7m0cru$jk8$1@engnews1.eng.sun.com>,
clamage@eng.sun.com (Steve Clamage) wrote:
> Not in the template sense. The name X will be bound to whatever
> X is visible. That X does not depend on the type of T.
A pity. Think of all the tax write-offs that would have been
possible if X was a dependant.
--
Allan_W@my-deja.com is a "Spam Magnet," never read.
Please reply in newsgroups only, sorry.
Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/07/13 Raw View
gbush@my-deja.com wrote:
>
> In article <7m2d3e$cul$1@nnrp1.deja.com>,
> Andrei Alexandrescu <andrewalex@hotmail.com> wrote:
> [snip]
> > I'm not sure. In the presence of overloading, one cannot say anything
> > about the name of a function. Consider this:
> >
> > void X(int);
> > void X(double);
> >
> > F<int>(); // will this work?
> >
> This sure works. It calls X(int). Why do you think there could be any
> problems with that?
> Here is the example I just compiled and ran:
> template < class T > void F(void (*p)(T) = X ) {p(0);}
> void X(int) {ShowMessage("X(int)");}
> void X(double) {ShowMessage("X(double)");}
> void foo()
> {
> F<int>(); // calls X(int)
> F<double>(); // calls X(double)
> }
This only proves that it works with the current version of
your current compiler.
The question, however, is if it works with the standard.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Lisa Lippincott <lisa_lippincott@advisories.com>
Date: 1999/07/08 Raw View
I asked:
> Consider this template:
> template < class T > void F( void (*p)(T) = X ) {...}
> Is X a dependent name?
Steve Clamage <clamage@eng.sun.com> confirms my suspicion:
> Not in the template sense. The name X will be bound to whatever
> X is visible. That X does not depend on the type of T.
[...]
> If X is not convertable to void(*)(T) for the T used in an
> instantiation, the code is in error.
Here's my situation: I expect the function X to be overloaded to
accept T. While it's reasonable to require the overload of X to be
in scope at the point of instantiation, it's not reasonable to expect
it to be in scope at the template's definition.
I don't see any way to write an expression which takes the address of X.
Is there a way?
Should there be a way?
--Lisa Lippincott
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/07/08 Raw View
Steve Clamage wrote:
>
> Lisa Lippincott <lisa_lippincott@advisories.com> writes:
>
> >Consider this template:
>
> >template < class T > void F( void (*p)(T) = X ) {...}
>
> >Is X a dependent name?
>
> Not in the template sense. The name X will be bound to whatever
> X is visible. That X does not depend on the type of T.
void X(int) {}
void X(double) {}
F<int>(); // should be equivalent to F<int>(X)
// which chooses void X(int)
F<double>(); // should be equivalent to F<double>(X)
// which chooses void X(double)
The point is that more than one function of the same name can be
visible, and which one is chosen depends on the context. And that
context depends on T.
>
> >I think it should be -- in non-template code, the referent of X would
> >vary with the type T.
>
> That's an issue for users of this template. If X is not convertable
> to void(*)(T) for the T used in an instantiation, the code is
> in error.
See the example above: Both F<int>() and F<double>() should be
allowed, and should choose different functions.
>
> > But I can't show from the standard that X is
> >dependent. In particular, there's nothing in 14.6.2.2 [temp.dep.expr]
> >that says that X is dependent.
>
> You just answered your own question. :-)
Does that mean the code above is ill-formed?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Andrei Alexandrescu <andrewalex@hotmail.com>
Date: 1999/07/09 Raw View
In article <7m0cru$jk8$1@engnews1.eng.sun.com>,
clamage@eng.sun.com (Steve Clamage) wrote:
> Lisa Lippincott <lisa_lippincott@advisories.com> writes:
>
> >Consider this template:
>
> >template < class T > void F( void (*p)(T) = X ) {...}
>
> >Is X a dependent name?
>
> Not in the template sense. The name X will be bound to whatever
> X is visible. That X does not depend on the type of T.
I'm not sure. In the presence of overloading, one cannot say anything
about the name of a function. Consider this:
void X(int);
void X(double);
F<int>(); // will this work?
> That's an issue for users of this template. If X is not convertable
> to void(*)(T) for the T used in an instantiation, the code is
> in error.
As I said, there are several X's.
Andrei
Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: gbush@my-deja.com
Date: 1999/07/09 Raw View
In article <7m2d3e$cul$1@nnrp1.deja.com>,
Andrei Alexandrescu <andrewalex@hotmail.com> wrote:
[snip]
> I'm not sure. In the presence of overloading, one cannot say anything
> about the name of a function. Consider this:
>
> void X(int);
> void X(double);
>
> F<int>(); // will this work?
>
This sure works. It calls X(int). Why do you think there could be any
problems with that?
Here is the example I just compiled and ran:
template < class T > void F(void (*p)(T) = X ) {p(0);}
void X(int) {ShowMessage("X(int)");}
void X(double) {ShowMessage("X(double)");}
void foo()
{
F<int>(); // calls X(int)
F<double>(); // calls X(double)
}
Gene.
Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: wmm@fastdial.net
Date: 1999/07/10 Raw View
In article <070719991258361828%lisa_lippincott@advisories.com>,
Lisa Lippincott <lisa_lippincott@advisories.com> wrote:
>
>
> Consider this template:
>
> template < class T > void F( void (*p)(T) = X ) {...}
>
> Is X a dependent name?
>
> I think it should be -- in non-template code, the referent of X would
> vary with the type T. But I can't show from the standard that X is
> dependent. In particular, there's nothing in 14.6.2.2 [temp.dep.expr]
> that says that X is dependent.
Even if X were dependent, it wouldn't do you any good. The only
extra lookup that is done for dependent names is a Koenig lookup
(argument-dependent lookup, 3.4.2) in namespaces from the
instantiation context (14.6.4); you don't get a normal lookup
there. Since the address of a function has no arguments, there is
no argument-dependent lookup and you would still find only the
Xs that were visible in the definition context, even if X were
dependent.
(Thanks to Erwin Unruh for pointing this out to me.)
--
William M. Miller, wmm@fastdial.net
Software Emancipation Technology (www.setech.com)
Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Lisa Lippincott <lisa_lippincott@advisories.com>
Date: 1999/07/10 Raw View
I wrote:
> template < class T > void F( void (*p)(T) = X ) {...}
Christopher Eltschka <celtschk@physik.tu-muenchen.de> added:
> void X(int) {}
> void X(double) {}
>
> F<int>(); // should be equivalent to F<int>(X)
> // which chooses void X(int)
> F<double>(); // should be equivalent to F<double>(X)
> // which chooses void X(double)
>
> The point is that more than one function of the same name can be
> visible, and which one is chosen depends on the context. And that
> context depends on T.
I think it's even worse than that. Since X is not a dependent name
in the template, it must be bound at the point of the template
definition. With the code arranged as above, X cannot refer to either
X(int) or X(double).
Looking further into the problem, I've found an approaches to solving
this problem, but it is not entirely satisfactory. One could use a local
declaration of the function:
template <class T> void (*)(T) AddressOfX()
{
void X(T);
return X;
}
This forces a declaration of X to b in scope at the point where the
non-dependent name is used. But, rather than using Koenig lookup
from the point of instantiation, I think this X can refer only to
functions in the same namespace as AddressOfX.
--Lisa Lippincott
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Lisa Lippincott <lisa_lippincott@advisories.com>
Date: 1999/07/07 Raw View
Consider this template:
template < class T > void F( void (*p)(T) = X ) {...}
Is X a dependent name?
I think it should be -- in non-template code, the referent of X would
vary with the type T. But I can't show from the standard that X is
dependent. In particular, there's nothing in 14.6.2.2 [temp.dep.expr]
that says that X is dependent.
--Lisa Lippincott
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: clamage@eng.sun.com (Steve Clamage)
Date: 1999/07/07 Raw View
Lisa Lippincott <lisa_lippincott@advisories.com> writes:
>Consider this template:
>template < class T > void F( void (*p)(T) = X ) {...}
>Is X a dependent name?
Not in the template sense. The name X will be bound to whatever
X is visible. That X does not depend on the type of T.
>I think it should be -- in non-template code, the referent of X would
>vary with the type T.
That's an issue for users of this template. If X is not convertable
to void(*)(T) for the T used in an instantiation, the code is
in error.
> But I can't show from the standard that X is
>dependent. In particular, there's nothing in 14.6.2.2 [temp.dep.expr]
>that says that X is dependent.
You just answered your own question. :-)
--
Steve Clamage, stephen.clamage@sun.com
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]