Template related question

L

LRS Kumar

The following code - from "C++ Templates: The Complete Guide" by
Vandevoorde/Josuttis - seems to compile with Borland C++. However it
fails to compile with other compilers - Comeau Online and g++. Any
idea why?

template<typename T>
class Shell {
public:
template<int N>
class In {
public:
template<int M>
class Deep {
public:
virtual void f(){}
};
};
};

template<typename T, int N>
class Weird {
public:
void case1(Shell<T>::template In<N>::template Deep<N>* p) {
p->template Deep<N>::f(); // inhibit virtual call
}
void case2(Shell<T>::template In<T>::template Deep<T>& p) {
p.template Deep<N>::f(); // inhibit virtual call
}
};


Thank you.
 
L

Leor Zolman

The following code - from "C++ Templates: The Complete Guide" by
Vandevoorde/Josuttis - seems to compile with Borland C++. However it
fails to compile with other compilers - Comeau Online and g++. Any
idea why?

template<typename T>
class Shell {
public:
template<int N>
class In {
public:
template<int M>
class Deep {
public:
virtual void f(){}
};
};
};

template<typename T, int N>
class Weird {
public:
void case1(Shell<T>::template In<N>::template Deep<N>* p) {
p->template Deep<N>::f(); // inhibit virtual call
}
void case2(Shell<T>::template In<T>::template Deep<T>& p) {
p.template Deep<N>::f(); // inhibit virtual call
}
};

This is actually in the errata for the book (which I only discovered after
figuring it all out for myself, and then turning to page 132 in the book,
only to find the errata I had forgotten I'd penciled in...)

That last section is supposed to say:
void case1(template Shell<T>::template In<N>::template Deep<N>* p) {
p->template Deep<N>::f(); // inhibit virtual call
}
void case2(template Shell<T>::template In<N>::template Deep<N>& p) {
p.template Deep<N>::f(); // inhibit virtual call

-leor
 
S

Sumit Rajan

Leor Zolman said:
On 8 Apr 2004 15:42:21 -0700, (e-mail address removed) (LRS Kumar) wrote:
This is actually in the errata for the book (which I only discovered after
figuring it all out for myself, and then turning to page 132 in the book,
only to find the errata I had forgotten I'd penciled in...)

That last section is supposed to say:

template<typename T, int N>
class Weird {
public:
void case1 (typename Shell<T>::template In<N>::template Deep<N>* p) {
p->template Deep<N>::f(); // inhibit virtual call
}
void case2 (typename Shell<T>::template In<N>::template Deep<N>& p) {
p.template Deep<N>::f(); // inhibit virtual call
}
};


Regards,
Sumit.
 
D

Daveed Vandevoorde

template<typename T, int N>
class Weird {
public:
void case1(Shell<T>::template In<N>::template Deep<N>* p) { ^ insert "typename " here
p->template Deep<N>::f(); // inhibit virtual call
}
void case2(Shell<T>::template In<T>::template Deep<T>& p) { ^ insert "typename " here
p.template Deep<N>::f(); // inhibit virtual call
}
};

There are two "typename " keywords missing.

My apologies for the error.

This particular one was fixed in the 2nd print.
You can see a list of known issues at
http://www.josuttis.com/tmplbook/errata.html

Daveed
 
V

Vikram Paranjape

Even that didn't compile for me on g++ 3.3.1
Here's what I had to change it to:

template<typename T, int N>
class Weird {
public:
void case1(typename Shell<T>::template In<N>::template Deep<N>* p) {
p->Deep<N>::f(); // inhibit virtual call
}
void case2(typename Shell<T>::template In<N>::template Deep<N>& p) {
p.Deep<N>::f(); // inhibit virtual call
}
};

Note that "p->template Deep<N>::f();" and "p.template Deep<N>::f();" have
both had the template keyword removed

Makes sense too, since the template keyword is used to declare templates. We
have already made it known that p in case 1 is a pointer to an object of
type Shell<T>::template In<N>::template Deep<N>. When we use p to access
methods from the interface of an object of that type, I suppose using the
keyword "template" must be an error

(Sorry for hitting "Reply" and not "Reply Group" on that last post)

Regards,
Vikram
 
L

Leor Zolman

Even that didn't compile for me on g++ 3.3.1
Probably a gcc bug.
Here's what I had to change it to:

template<typename T, int N>
class Weird {
public:
void case1(typename Shell<T>::template In<N>::template Deep<N>* p) {
p->Deep<N>::f(); // inhibit virtual call
}
void case2(typename Shell<T>::template In<N>::template Deep<N>& p) {
p.Deep<N>::f(); // inhibit virtual call
}
};

Note that "p->template Deep<N>::f();" and "p.template Deep<N>::f();" have
both had the template keyword removed

Clearly, then, gcc has trouble with the "template" keyword. It compiles
without error using Comeau, MSVC 7 and 7.1, Borland (even free command
line tools), CodeWarrior 8, and Digital Mars.
-leor
 
R

Rob Williscroft

Vikram Paranjape wrote in
Even that didn't compile for me on g++ 3.3.1
Here's what I had to change it to:

template<typename T, int N>
class Weird {
public:
void case1(typename Shell<T>::template In<N>::template Deep<N>* p)
{
p->Deep<N>::f(); // inhibit virtual call
}
void case2(typename Shell<T>::template In<N>::template Deep<N>& p)
{
p.Deep<N>::f(); // inhibit virtual call
}
};

Note that "p->template Deep<N>::f();" and "p.template Deep<N>::f();"
have both had the template keyword removed

Makes sense too, since the template keyword is used to declare
templates. We have already made it known that p in case 1 is a pointer
to an object of type Shell<T>::template In<N>::template Deep<N>. When
we use p to access methods from the interface of an object of that
type, I suppose using the keyword "template" must be an error

Makes sence to us maybe, however g++ is wrong here, this shows why:

struct X
{
int Deep;
};

int f() { return 3; }

template<typename T>
class Shell
{
public:
template<int N>
class In
{
public:
template<int M>
class Deep : public X
{
public:
virtual void f(){}
};
};
};

template<typename T, int N>
class Weird
{
public:
void case1(typename Shell<T>::template In<N>::template Deep<N>* p)
{
p->Deep<N>::f(); // inhibit virtual call
}

void case2(typename Shell<T>::template In<N>::template Deep<N>& p)
{
p.Deep<N>::f(); // inhibit virtual call
}
};


int main()
{
Weird< int, 3 > w;
Shell< int >::In< 3 >::Deep< 3 > arg;

w.case1( & arg );
w.case2( arg );
}

Both VC 7.1 and CBuilderX (preview) compile the above, the programme
does exhibit UB, but thats only 'cause I didn't bother to initialize
X::Deep.;)

If you put the template back into p.Deep<N>::f(), CBuilderX still
compiles (*), VC and g++ (3.2 and 3.4 (prerelease **)) all fail to
compile.

*) I think it should, but I wouldn't bet on it, also I don't
really care as the above (modified) code is mostly nonsence.

**) The gcc 3.4 prerelease is quite old now, a later version may
behave differently.

Rob.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,754
Messages
2,569,521
Members
44,995
Latest member
PinupduzSap

Latest Threads

Top