Can anyone give me a definitive answer on whether the code below should
compile or not?
template <typename T>
struct A
{
typedef T Type;
void f(Type) {}
};
template <typename T>
struct B : A<T>
{
typedef typename A<T>::Type Type;
void ff(Type t) { f(t); } // XXX
};
template struct B<int>;
GCC 3.4 accepts it, Comeau's online compiler does not, telling me that
"f" has not been declared on the line marked "XXX". Emails to both
parties were answered with a quick reply saying "we got it right", which
doesn't help me much :)
Vandevoorde and Josuttis doesn't make it clear either (unless I missed
something). I understand the concept of a dependent name, and what must
be done to delay lookup until the second-phase - but I don't understand
whether "f" above _is_ a dependent name. AFAICT it should be, because
the argument passed to it is of type "Type", which is dependent (hence
the "typename" in the line above XXX). Is taking a dependent type as an
argument not enough to make a name dependent? Why not?
My reading of 14.6.2 implies that the identifier "f" should be considered
dependent in the XXX context, because the function argument was declared
with a dependent-type and so is a type-dependent expression. Am I wrong?
The error can be avoided by the usual methods, replacing "f" with
"this->f" or "A<T>::f", but I'd like to understand why that's necessary
here.
Here's another example, which extends the code above:
template <typename T>
struct C
{
void g(A<T>*) {}
};
template <typename T>
struct D : C<T>
{
B<T> b;
void gg() { g(&b); } // XXX
};
template struct D<int>;
Same situation, GCC accepts it but Comeau errors on the line marked XXX.
Here AFAICT the argument is of type "pointer to dependent type", but that
still makes the "g" identifier dependent on "T".
Please help, this has been bugging me for weeks!
TIA,
jon
--
(remove -SPAM to mail me)
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
> template <typename T>
> struct A
> {
> typedef T Type;
> void f(Type) {}
> };
>
> template <typename T>
> struct B : A<T>
> {
> typedef typename A<T>::Type Type;
> void ff(Type t) { f(t); } // XXX
> };
>
> template struct B<int>;
>
> GCC 3.4 accepts it, Comeau's online compiler does not, telling me that
> "f" has not been declared on the line marked "XXX". Emails to both
> parties were answered with a quick reply saying "we got it right", which
> doesn't help me much :)
A later reply to my to the GCC list explains that the above isn't legal.
(Como's right as usual :-)
The name is dependent, but 14.6.2 -3- says that the dependent base
A<T> is not examined when looking up unqualified names, neither at the
point of definition nor at the point of instantiation. So although the
name is dependent, and IIUC lookup is delayed until the second-phase,
it still isn't found because it's not qualified.
This seems to have changed between the final draft standard and TC1
of the standard. At one point the base class was examined at the
point of instantiation. After digging out my hardcopy of 14882:2003 I
see why Como is right and see that I should check the final standard
not a draft :-|
jon
--
(remove -SPAM to reply)
It should not. The reference in the standard is 14.6.2/3 which
says:
In the definition of a class template or a member of a class template,
if a base class of the class template depends on atemplate-parameter,
the base class scope is not examined during unqualified name lookup
either at the point of definition of the class template or member or
during an instantiation of the class template or member.
Note the "or during an instantiation" part. I.e., unlike other contexts,
having an unqualified dependent name doesn't actually help in this
case. Only qualified lookup will do.
> template <typename T>
> struct A
> {
> typedef T Type;
> void f(Type) {}
> };
>
> template <typename T>
> struct B : A<T>
> {
> typedef typename A<T>::Type Type;
> void ff(Type t) { f(t); } // XXX
> };
>
> template struct B<int>;
>
> GCC 3.4 accepts it, Comeau's online compiler does not, telling me that
> "f" has not been declared on the line marked "XXX". Emails to both
> parties were answered with a quick reply saying "we got it right", which
> doesn't help me much :)
>
> Vandevoorde and Josuttis doesn't make it clear either (unless I missed
> something).
Hmm, I should correct 9.4.2, which is indeed misleading.
> I understand the concept of a dependent name, and what must
> be done to delay lookup until the second-phase - but I don't understand
> whether "f" above _is_ a dependent name. AFAICT it should be, because
> the argument passed to it is of type "Type", which is dependent (hence
> the "typename" in the line above XXX). Is taking a dependent type as an
> argument not enough to make a name dependent? Why not?
>
> My reading of 14.6.2 implies that the identifier "f" should be considered
> dependent in the XXX context, because the function argument was declared
> with a dependent-type and so is a type-dependent expression. Am I wrong?
You're right, but that doesn't help in this case.
> The error can be avoided by the usual methods, replacing "f" with
> "this->f" or "A<T>::f", but I'd like to understand why that's necessary
> here.
>
> Here's another example, which extends the code above:
>
> template <typename T>
> struct C
> {
> void g(A<T>*) {}
> };
>
> template <typename T>
> struct D : C<T>
> {
> B<T> b;
> void gg() { g(&b); } // XXX
> };
>
> template struct D<int>;
>
> Same situation, GCC accepts it but Comeau errors on the line marked XXX.
>
> Here AFAICT the argument is of type "pointer to dependent type", but that
> still makes the "g" identifier dependent on "T".
>
> Please help, this has been bugging me for weeks!
Only qualification (possibly indirectly through a using-declaration)
will cause lookup in dependent base classes.
Daveed
Well, our response also said:
"you can address this:
* Qualify by use of this->
You can also:
* Qualify the calls with the respective base class name
* Use a using directive with the respective base class name
You should also be able to get it to compile with Comeau by:
* Using non-strict mode
* Specifying --no_dep_name, even in strict mode
though these two are obviously not conforming."
Re gcc, I haven't tried it but you may want to see how it
fares with -Wall -ansi -pendantic requests.
>Vandevoorde and Josuttis doesn't make it clear either (unless I missed
>something). I understand the concept of a dependent name, and what must
>be done to delay lookup until the second-phase - but I don't understand
>whether "f" above _is_ a dependent name. AFAICT it should be, because
>the argument passed to it is of type "Type", which is dependent (hence
>the "typename" in the line above XXX). Is taking a dependent type as an
>argument not enough to make a name dependent? Why not?
>
>My reading of 14.6.2 implies that the identifier "f" should be considered
>dependent in the XXX context, because the function argument was declared
>with a dependent-type and so is a type-dependent expression. Am I wrong?
That's fine, however, this issues here isn't one of dependency
per se, but how lookup should occur.
>The error can be avoided by the usual methods, replacing "f" with
>"this->f" or "A<T>::f", but I'd like to understand why that's necessary
>here.
>
>Here's another example, which extends the code above:
>
> template <typename T>
> struct C
> {
> void g(A<T>*) {}
> };
>
> template <typename T>
> struct D : C<T>
> {
> B<T> b;
> void gg() { g(&b); } // XXX
> };
>
> template struct D<int>;
>
>Same situation, GCC accepts it but Comeau errors on the line marked XXX.
>
>Here AFAICT the argument is of type "pointer to dependent type", but that
>still makes the "g" identifier dependent on "T".
This should be helpful... let's see.. check out 14.6.2p3.
In short, your original call to f() is not qualified, it's
unadorned, but in that context that's not enough.
--
Greg Comeau / Comeau C++ 4.3.3, for C++03 core language support
Comeau C/C++ ONLINE ==> http://www.comeaucomputing.com/tryitout
World Class Compilers: Breathtaking C++, Amazing C99, Fabulous C90.
Comeau C/C++ with Dinkumware's Libraries... Have you tried it?
[...]
| Re gcc, I haven't tried it but you may want to see how it
| fares with -Wall -ansi -pendantic requests.
GCC (even in its latest incarnation) gets this wrong as I explained
on the GCC mailing list where the question was originally asked.
--
Gabriel Dos Reis
g...@integrable-solutions.net