Skip to main content
gamedev.net
🔒 Locked

C++ template class problem

Started by Timkin 11 replies 750+ views
Original Post
Timkin
Timkin
Mmm, having a problem with some older code I wrote that I know compiled with a previous compiler I had, but cannot get it to compile in VC++ .NET (2003), which I'm now compelled to use. Any help on how to correct this situation would be very much appreciated (and an explanation of why it doesn't work in MS VC++ too please!)!

template <class T> class foo{
  private:
       class bar{
          public:
             T*   pObj;
       };

       bar*     pThing;

  public:
       bar*     getThing();
};

template <class T>
bar* foo<T>::getThing(){
 return pThing;
};

The error(s) reported are related to the function definition for getThing(). Specifically, the line bar* foo<T>::getThing() fails with: 'syntax error: missing ';' before '*' 'bar': missing storage-class or type specifiers 'T' undeclared identifier 'foo': use of class template requires template argument list So my presumption is that the compiler doesn't see 'bar' as a type (as evidenced by the second error). Is this the cause? How do I correctly set up this situation in MS VC++ (2003) where I need a member function that returns a pointer to a nested class type, where the nested class exists within a template class. FYI: getThing would be used in a context to subsequently access the thing stored in pObj. (and yes, this is part of a customised storage class that cannot trivially be made using the STL). Cheers, Timkin
Kuladus
Kuladus
I recall needing the "typename" keyword to resolve this situation. Try
template <class T>typename bar* foo<T>::getThing(){ return pThing;};
Polymorphic OOP
Polymorphic OOP
template <class T> class foo{  private:       class bar{          public:             T*   pObj;       };       bar*     pThing;  public:       bar*     getThing();};template <class T>typename foo<T>::bar* foo<T>::getThing(){ return pThing;}
Timkin
Timkin
You guys are legendary. Thanks for the very quick (and correct) response. Works just fine now.

So, WHY is this the case with MS's compiler, or is it just one of those things that MS requires so that they're different from everyone else? ;)

Thanks again,

Timkin
Conner McCloud
Conner McCloud
Quote:
Original post by Timkin
You guys are legendary. Thanks for the very quick (and correct) response. Works just fine now.

So, WHY is this the case with MS's compiler, or is it just one of those things that MS requires so that they're different from everyone else? ;)

Thanks again,

Timkin

I know gcc only just recently started requiring you to use typename...before, it was optional in most cases. Why VS requires it here and nowhere else you'll have to wait for the smarter folks to chime in for.

CM
Oluseyi
Oluseyi
Quote:
Original post by Timkin
So, WHY is this the case with MS's compiler, or is it just one of those things that MS requires so that they're different from everyone else? ;)

What other compilers accept the previous input? I don't think that bar should be visible outside the foo namespace, and any compiler that accepts that is broken. As for the typename requirement, I don't actually know (and I consider it harmful to speculate [smile]).

And it's common knowlegde that, in terms of the 1997/8 C++ Standard, VS6 is broken. Of course it is, it predates the standard by a good year or three.

I think it's actually a sign of VS.NET's increased standards compliance.
joanusdmentia
joanusdmentia
Quote:
or is it just one of those things that MS requires so that they're different from everyone else?

Exact opposite actually, the changes are a result of MS making their C++ compiler more compliant with the standard. The reason for needing the typename keyword is that because of template specialization you don't know for sure *what* foo<T>::bar is, it might be a type, a variable or a function.

For example:
template<typename T>struct foo{    typedef T bar;};template<>struct foo<int>{    T bar;};template<typename T>struct morefoo{    foo<T>::bar value; // what if T is int!?};
"Voilà! In view, a humble vaudevillian veteran, cast vicariously as both victim and villain by the vicissitudes of Fate. This visage, no mere veneer of vanity, is a vestige of the vox populi, now vacant, vanished. However, this valorous visitation of a bygone vexation stands vivified, and has vowed to vanquish these venal and virulent vermin vanguarding vice and vouchsafing the violently vicious and voracious violation of volition. The nly verdict is vengeance; a vendett o
Conner McCloud
Conner McCloud
Quote:
Original post by Oluseyi
And it's common knowlegde that, in terms of the 1997/8 C++ Standard, VS6 is broken. Of course it is, it predates the standard by a good year or three.

He's using 2003, though, which is considerably better that VS6.
Quote:
Original post by Oluseyi
I think it's actually a sign of VS.NET's increased standards compliance.

Not really...in general, typename is still completely optional, at least in the 2003 version of the compiler [can't speak for the most recent release, as I don't have it]. Its just once in a while that it gets confused and bails if you forget it.

At the moment, the only think keeping most of my code from compiling unchanged in both gcc and VS is my complete failure to use typename properly. At least gcc gives you an intelligent error, though...basically says "add a typename here, silly" rather than a string of undefined identifiers, so the actual fix is pretty straight forward.

*edit: I think I'm mistaken...VS isn't as lax here as I thought. joanusdmentia's code doesn't compile in VS2003, and I was quite certain it would. This makes me wonder if avoidance of these errors isn't just blind luck, rather than a specific failure on VSs part...I don't do much template work, and it has been a while since last tried such a cross compilation. Perhaps I hadn't upgraded from 6.0 yet. My apologies for any misunderstanding.

CM

[Edited by - Conner McCloud on October 30, 2005 1:13:28 AM]
Conner McCloud
Conner McCloud
Quote:
Original post by joanusdmentia
Quote:
or is it just one of those things that MS requires so that they're different from everyone else?

Exact opposite actually, the changes are a result of MS making their C++ compiler more compliant with the standard. The reason for needing the typename keyword is that because of template specialization you don't know for sure *what* foo<T>::bar is, it might be a type, a variable or a function.

For example:
*** Source Snippet Removed ***

In your example, though, it does have to be a type, or there will be a syntax error when you go to compile the code.

What makes that example any different from this:
template<class T>T test(){    T a;    a.push_back(1.0);    return a;}int main(){    test<vector<double> >(); //OK    test<double>(); //error C2228: left of '.push_back' must have class/struct/union type}


CM
joanusdmentia
joanusdmentia
Quote:
Original post by Conner McCloud
In your example, though, it does have to be a type, or there will be a syntax error when you go to compile the code.

What makes that example any different from this:
*** Source Snippet Removed ***

CM


The difference is the compiler's ability to produce a meaningful error message. When using function templates you only have 1 layer of complexity, that is T may not provide the required push_back() method. However, try working out where the problem is when when A<T1>::some::thing::value_type doesn't provide the required push_back() method. While my example may be simple enough, I'm sure we can all remember the fun we had wading through the pages of error messages in VS6.
"Voilà! In view, a humble vaudevillian veteran, cast vicariously as both victim and villain by the vicissitudes of Fate. This visage, no mere veneer of vanity, is a vestige of the vox populi, now vacant, vanished. However, this valorous visitation of a bygone vexation stands vivified, and has vowed to vanquish these venal and virulent vermin vanguarding vice and vouchsafing the violently vicious and voracious violation of volition. The nly verdict is vengeance; a vendett o
Polymorphic OOP
Polymorphic OOP
Quote:
Original post by joanusdmentia
The reason for needing the typename keyword is that because of template specialization you don't know for sure *what* foo<T>::bar is, it might be a type, a variable or a function.

Also, even without specializations, the need for typename and template as disambiguators still exist in many other situations, it's just that places where dependent types can occur are a little more limitted, particularly this situation wouldn't require it. For instance, if you need to access a type or template member of a template argument, you'd still need to use typename or template as a disambiguator if the language had no concept of specialization.
Conner McCloud
Conner McCloud
Quote:
Original post by joanusdmentia
The difference is the compiler's ability to produce a meaningful error message. When using function templates you only have 1 layer of complexity, that is T may not provide the required push_back() method. However, try working out where the problem is when when A<T1>::some::thing::value_type doesn't provide the required push_back() method. While my example may be simple enough, I'm sure we can all remember the fun we had wading through the pages of error messages in VS6.

Hmmm...OK, that's fair enough. Coupled with my recent realization that MS has chosen to require it as well, I suppose I need to start taking it a bit more seriously.

CM

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.