I have a problem with a template and pointers ( I think ). Below is the part of my code:
/* ItemCollection.h */
#ifndef ITEMCOLLECTION_H
#define ITEMCOLLECTION_H
#include <cstddef>
using namespace std;
template <class T> class ItemCollection
{
public:
// constructor
//destructor
void insertItem( const T );
private:
struct Item
{
T price;
Item* left;
Item* right;
};
Item* root;
Item* insert( T, Item* );
};
#endif
And the file with function defintion:
/* ItemCollectionTemp.h-member functions defintion */
#include <iostream>
#include <cstddef>
#include "ItemCollection.h"
template <class T>
Item* ItemCollection <T>::insert( T p, Item* ptr)
{
// function body
}
Here are the errors which are generated by this line of code:
Item* ItemCollection <T>::insert( T p, Item* ptr)
Errors:
error C2143: syntax error : missing ';' before '*'
error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
error C2065: 'Type' : undeclared identifier
error C2065: 'Type' : undeclared identifier
error C2146: syntax error : missing ')' before identifier 'p'
error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
error C2470: 'ItemCollection::insert' : looks like a function definition, but there is no parameter list; skipping apparent body
error C2072: 'ItemCollection::insert': initialization of a function
error C2059: syntax error : ')'
Any help is much appreciated.
The short answer is what Alexey already posted:
template <typename T>
typename ItemCollection<T>::Item* ItemCollection<T>::insert( T p, Item * ptr ) {
// ...
}
(To understand why typename
is required, search SO for related questions, or else drop a comment. I will focus the answer in the lookup rules that explain why the return and the argument types must be declared differently)
The explanation is that the lookup rules in c++ have different scopes for the return type and the rest of the parameters. When the compiler sees the definition A B::c( D )
, A
is checked in the enclosing namespace of the definition, as is B
. When the compiler finds ::c
it looks up c
inside class B
. At that point, the rest of the definition is inside the scope of the class B
for the rest of parameters. That means that if the return type is an internal type of the class, you have to use the qualified name for the return type, while in the case of D
the compiler will first look it up inside the class B
.
That explains why the return type must be fully qualified even if the last parameter is not. When the parameter Item * ptr
is found by the compiler, it is already in the scope of the class, and it will find it there. On the other hand, there is no Item
defined in the enclosing namespace.
One of the changes in the upcomming standard will deal with this, even if it was not designed with this purpose in mind. If I recall correctly, the following syntax should compile without the full type qualification:
template <T>
auto ItemCollection<T>::insert( T p, Item * ptr ) -> Item *
{
return 0;
}
The reason is exactly the same. After ItemCollection<T>::insert
has been parsed the remainder tokens will be verified inside the ItemCollection<T>
scope, including the -> Item *
return definition.
template <class T>
typename ItemCollection <T>::Item* ItemCollection<T>::insert( T p, Item* ptr)
{
// function body
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With