Murali Medisetty
Murali Medisetty

Reputation: 51

What's wrong with the following Code

I am trying to compile the following snippets of code. Please check the errors I am getting at the end.

#include "Tree.h"

template <class T>
CNode<T>* CNode<T>::GetChild(const T& kData)
{
    for( std::vector< CNode >::iterator it = m_vChildren.begin(); it!= m_vChildren.end(); ++it)
    {
        if(*it== kData)
        {
           return &(*it);
        }
    }
}

Tree.h (Header file):

#include "../include_m.h"
#include <vector>

template <class T>
class CNode
{
 public:
    CNode(const T& kData)
    {
        m_Data = kData;
    }

    void AddChildNode(const CNode& kcChildNode);
    void DeleteChildNode(const T& kData);
    void GetChildNode(const T& kData) const;
    void Print();

 private:
    T                       m_Data;
    std::vector<CNode>      m_vChildren;

    CNode * GetChild(const T& kData);
};

This fails to compile with the following errors:

g++ -o tree Tree.cpp 
Tree.cpp: In member function ‘CNode<T>* CNode<T>::GetChild(const T&)’:
Tree.cpp:12: error: expected `;' before ‘it’
Tree.cpp:12: error: ‘it’ was not declared in this scope

Upvotes: 0

Views: 124

Answers (2)

enobayram
enobayram

Reputation: 4708

All you're missing is a typename before std::vector< CNode >::iterator. Since CNode<T>::GetChild is a templated context, the compiler can't know whether std::vector< CNode >::iterator is a type or a value member. You could for instance have a template specialization of std::vector<CNode<int> > where iterator is defined as a class field. You need to use the typename keyword to resolve this ambiguity.

On a relevant note, there's an even trickier situation where you need the template keyword, and it might be worth mentioning here, consider:

template <class T>
struct C {
   template <class U>
   void memfunc();
};

template <class T>
void func() {
   C<T> c;
   c.template memfunc<int>();
}

You need the odd template keyword in the last line there, since due to a similar reason to your problem, the compiler can't know that the member is in fact a template method in all specializations of the class C. The error messages you get with this is also quite odd and they puzzle me every time.

The other answers also have a relevant point about having a template definition in a .cpp file. You should probably follow their advice and move the definition to a .h file. However, there actually are circumstances where you want a template definition in a .cpp file. For instance, it might be that the method is only used in the same .cpp file. Or you might want to take control of what types you want the templated member function to be instantiated with using explicit instantiation. You would achieve this with:

template class CNode<int>; // explicitly instantiate CNode<int> 
template CNode<double>* CNode<double>::GetChild(const double& kData); // explicitly instantiate only the GetChild method for CNode<double>

This way, you won't have to recompile every .cpp file that includes tree.h whenever you make a change to the implementation of the GetChild method.

Upvotes: 2

Jimmy Thompson
Jimmy Thompson

Reputation: 1004

  1. You can't use a .cpp file with a template class. Everything must be in the .h.
  2. You're using references to CNode in your header to indicate return types, values placed inside std::vectors and parameters. These all have to be changed to CNode<T>.

This is because CNode does not exist as a class in itself, but rather a template for classes to be created from at compile time. For every type placed inside <T>; a new class is created at compile time.

Meaning CNode<X> is not the same class as CNode<Y>, and CNode does not exist at all in the binary/executable.

This means that you can never reference CNode, or its members, without providing a value for <T>.

Upvotes: 0

Related Questions