views:

109

answers:

7

With this code (just a class of test):

typedef unsigned short UInt16;

template<class T>
class CClass
{
public:
    SValue* getNewSValue(void);
private:
    typedef struct {
        T *mValue;
        T *next;
        T *previous;
        UInt16 index;
    } SValue;
};

template<typename T>
SValue* CClass<T>::getNewSValue(void)
{
    return new SValue;
}

I have the following errors:

error C2143: syntax error : missing ';' before '*'

error C4430: missing type specifier - int assumed. Note: C++ does not support default-int

Is it possible to use a Struct within a class? If I declare the struct out of the class the template doesn't see the template T.

A: 

It looks like your struct is not defined when you declare the return type of getNewSValue.

With that you don't have that error:

template<class T>
class CClass
{
public:
    SValue* getNewSValue(void);
private:
    typedef struct {
        T *mValue;
        T *next;
        T *previous;
        UInt16 index;
    } SValue;
};

template<typename T>
SValue* CClass<T>::getNewSValue(void)
{
  return new SValue;
}

And you also have to qualify the SValue return type, because it is nested in CClass when you use it to define getNewSValue.

Cedric H.
A: 

Declare SValue before getNewSValue():

template<class T> 
class CClass 
{ 
private: 
    typedef struct { 
        T *mValue; 
        T *next; 
        T *previous; 
        UInt16 index; 
    } SValue; 
public: 
    SValue* getNewSValue(void); 
}; 

Also, make sure UInt16 is defined.

In silico
+2  A: 

$9.2/2- The key is the below quote from the C++ Standard03

`A class is considered a completely-defined object type (3.9) (or complete type) at the closing } of the class-specifier. Within the class member-specification, the class is regarded as complete within function bodies, default arguments and constructor ctor-initializers (including such things in nested classes). Otherwise it is regarded as incomplete within its own class member-specification.

Don't know what is UINT16, but the following should work

template<class T> 
class CClass 
{ 
private: 
    typedef struct { 
        T *mValue; 
        T *next; 
        T *previous; 
        short int index;                      // Replacing with int for illustration only
    } SValue; 
public:
    SValue* getNewSValue(void); 
private: 
}; 

EDIT 3: The *** came there trying to make the change BOLD (which I should have deleted anyways)

template<class T> typename CClass<T>::SValue* CClass<T>::getNewSValue(void) 
{ 
    return new SValue; 
}

int main(){
    CClass<int> s;
    s.getNewSValue();
}
Chubsdad
What is the purpose of the `typename` keywork in the definition of `getNewSValue` ? That's because SValue is unnamed and we have to refer to it using the `typedef` name ?
Cedric H.
@Cedric if we would omit `typename`, it would be parsed like the definition of a member called `SValue` of class `CClass<T>`, for which no type was specified: `tempate<class T> Class<T>::SValue;`. The tokens following would be junk and rejected by the compiler as syntax errors. This all is because the compiler by default assumes non-types if it can't lookup a name at parse time (i.e it doesn't know what `T` is yet, so it can't lookup `SValue`). If you put `typename`, `SValue` is correctly regarded as a typename for the member `getNewSValue`.
Johannes Schaub - litb
The code you put generates the following error: "error C2244: 'CClass<T>::getNewSValue' : unable to match function definition to an existing declaration"
okami
@Johannes: Thanks !
Cedric H.
for a while you confused me with the triple pointers (\*'s). I think it should be SValue* and not SValue***
hype
@hype: Yes, it is my fault. I was trying to make it BOLD and then decided not to do it. So I manually removed the leading ** but forgot the trailing ones :(Have edited my post accordingly
Chubsdad
A: 

how about trying this ? it worked on VS2008

template<class T>
class CClass
{
private:
    typedef struct {
        T *mValue;
        T *next;
        T *previous;
        __int16 index;
    } SValue;

public:
    SValue* getNewSValue(void)
    {
        return new SValue;
    }
};
YeenFei
A: 

The SValue-Type is inside the CClass-namespace. You need to fully qualify the typename outside the class.

template<typename T>
CClass<T>::SValue* CClass<T>::getNewSValue(void)

Also, you should make SValue public, if it is returned by a public method.

Markus Kull
A: 

For the record, none of these will compile (on GCC 4.2 at least) as soon as a call to getNewSValue() is called. Since it's a public method that returns a pointer to a private type, you'll get a compile error stating that SValue is private.

In order for this to work, you'll either need to make SValue public, or change the type of the return value of getNewSValue() to something like void*, since it seems you're trying to make SValue an opaque type.

Bryan Ross
+1  A: 

Since the member function definition is in global scope, you need to qualify its return type with CClass:: to refer to the name within class scope. Also, the typename keyword is needed when referring to typenames nested within templates.

template<typename T>
typename CClass<T>::SValue* CClass<T>::getNewSValue(void)

Also, the nested struct is unnamed. Note that in C++, classes and structs have proper names, and a typedef name is not a class name. You will be much better off avoiding the typedef.

struct SValue {
    T *mValue;
    T *next;
    T *previous;
    UInt16 index;
};
Potatoswatter
This is very verbose :-), But Potatos your code generates the following err, on the line: typename CClass<T>::SValue* CClass<T>::getNewSValue(void) ERROR ---> "error C2899: typename cannot be used outside a template declaration"
okami
@okami: keep the `template< typename T >` part. For less verbose syntax, define the function inside the `class {}` scope. Then `typename` and qualification (on class-local types) aren't needed.
Potatoswatter