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

Template compiler error

11 views
Skip to first unread message

mlimber

unread,
Jul 25, 2005, 8:12:47 PM7/25/05
to
The following code is a reduced version of my real code and does not
compile on various platforms (Comeau online, and EDG online at
Dinkumware.com, g++ 3.4.1, TI Code Composer, but not .NET '03 online at
Dinkumware.com or Visual C++ 6). The errors are noted in comments:

template<typename T, typename>
class A
{
public:
void AFunc() const {}

protected:
A() {} // Must be subclassed to be instantiated
T t_;
};

template <typename T>
struct B
{
struct C { int j; };
struct D : public A<int,C>
{
int DFunc()
{
AFunc(); // Error: AFunc undefined!
return t_; // Error: t_ undefined!
}
};

D d_;
};

// Instantiate B
B<int> b;

I can get things to compile by:

1. Putting the compiler in "relaxed" mode in g++ or Comeau,
2. Making C a non-nested class by putting it at namespace/file scope,
3. Changing the template parameters to A (e.g., change a line above to
"struct D : public A<int,int>"), or
4. Making B a non-template class.

Obviously, none of these solutions is ideal. Any suggestions or ideas
why this happens?

M


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Ganny

unread,
Jul 26, 2005, 2:55:42 AM7/26/05
to
The name in template base class is not visible according to the
Standard lookup rules (See [temp.dep], 14.6.2(3) ). You can make it
visible by adding this before AFunc and t_.

-Ganesh.

Hyman Rosen

unread,
Jul 26, 2005, 2:53:07 AM7/26/05
to
mlimber wrote:
> Any suggestions or ideas why this happens?

Two-phase name lookup. To fix it, write Dfunc like this:
int Dfunc()
{
A<int,C>::AFunc();
return A<int,C>::t_;
}
But, you ask, where is the dependent name which causes the
delayed lookup? It's in 14.6.1/2d: "Within the scope of a
class template, when the unqualified name of a nested class
of the class template is referred to, it is equivalent to
the name of the nested class qualified by the name of the
enclosing class template." So what you actually have is


template <typename T>
struct B
{
struct C { int j; };

struct D : public A<int, typename B<T>::C>


{
int DFunc()
{
AFunc(); // Error: AFunc undefined!
return t_; // Error: t_ undefined!
}
};
D d_;
};

That makes D's base class a dependent name, and that
triggers the problem, even though it's not possible
for C to be anything but the struct C you've written.

Vladimir Marko

unread,
Jul 26, 2005, 2:54:26 AM7/26/05
to
mlimber wrote:
[...]

> template<typename T, typename>
> class A
> {
> public:
> void AFunc() const {}
>
> protected:
> A() {} // Must be subclassed to be instantiated
> T t_;
> };
>
> template <typename T>
> struct B
> {
> struct C { int j; };
> struct D : public A<int,C>
> {
> int DFunc()
> {
> AFunc(); // Error: AFunc undefined!
> return t_; // Error: t_ undefined!

Inside a template definition there are dependent and non-dependent
names (which do or don't depend on the template parameters). AFunc
and t_ in your statements are non-dependent and as such are looked
up when parsing the template definition. You want these names to be
found in the base class A<int,C>, but C is B<T>::C, i.e. a dependent
name and thus A<int,C> is a dependent base of D. The problem is that
dependent bases are not examined for non-dependent names. To solve
the problem make these names dependent. The easiest possibility is
to use "this->":
this->AFunc();
return this->t_;
The other possibility is explicit qualification:


A<int,C>::AFunc();
return A<int,C>::t_;

> }
> };
>
> D d_;
> };
[...]

Vladimir Marko

mlimber

unread,
Jul 27, 2005, 11:17:18 AM7/27/05
to
Hyman Rosen wrote:
[snip]

> But, you ask, where is the dependent name which causes the
> delayed lookup? It's in 14.6.1/2d: "Within the scope of a
> class template, when the unqualified name of a nested class
> of the class template is referred to, it is equivalent to
> the name of the nested class qualified by the name of the
> enclosing class template." So what you actually have is
[snip]

> That makes D's base class a dependent name, and that
> triggers the problem, even though it's not possible
> for C to be anything but the struct C you've written.

Thanks to you and all who answered. That helps. (I forgot to mention
that explicitly qualifying the inherited members also allows the code
to compile. While that's not an unacceptable solution from a design
perspective, it was aesthetically displeasing in the real context.)

A follow-up question: This two-stage name lookup is likely there for a
good reason. Just for edification, can someone give me an example or
two where the rule helps rather than hinders?

Cheers!

M

0 new messages