Link to home
Start Free TrialLog in
Avatar of anthon007r
anthon007r

asked on

Migration of template class from unmanaged to managed

I have this template classes that make use of STL.
I'm trying to make a DLL or a class library project type in vs.net 2003.
I want my template classes be exposed by including it to the project so that when I need the functionality of my class, ill just add a reference to the DLL.
Please give me how-to's and examples.
Thanks.
Avatar of AlexFM
AlexFM

Templates cannot be exported from Dll. The only way to expose template classes is to give set of h-files with full source code. This is a way how template libraries like STL, ATL are shipped.
The reason of this that template class is not real C++ class. It is not compiled by C++ compiler, and cannot be written to .obj file and linked to library. C++ compiler only makes basic syntax check of templated class.
Template becomes real C++ class, which can be compiled and linked, only when it is instantiated in the client code. At this point compiler needs full template source code.

// This is not real class
template <class T>
class A
{
};

class A<int> a;    // A<int> is real class which can be compiled
Avatar of anthon007r

ASKER

thanks AlexFM, but what am I going to do now? Could you please elaborate the this:

class A<int> a;    // A<int> is real class which can be compiled

because im having an error.. and how am i going to transform my classes so that it will be able to be exposed in DLL?
Does it mean I cannot use STL anymore?
Please help. Thanks.
Please show some code fragments, what classes do you want to export from Dll?
ok here it is..

#include "TreeNode.h"

template<class Type>
class CTTree
{

public:

////// Constructors

      CTTree();

////// Destructors

      ~CTTree();

////// Data members

      CTTreeNode<Type>* m_root;

      CTTreeNode<Type>* m_inOrderTraverser;
      CTTreeNode<Type>* m_preOrderTraverser;
      CTTreeNode<Type>* m_postOrderTraverser;

      unsigned char m_chInOrderStat; // monitors InOrder traversals
      unsigned char m_chPreOrderStat;
      unsigned char m_chPostOrderStat;

      enum E_TraversalType { e_ttInOrder = 1, e_ttPreOrder, e_ttPostOrder, e_ttAll }; //e_tt prefixed
      enum E_TraversalStat { e_tsFirstTime = 1, e_tsLeftTraversal, e_tsRightTraveral, e_tsRootTraversal, e_tsFinished }; //e_ts prefixed
      enum E_EnumerateLeafOrder { e_elLeftToRight = 1, e_elRightToLeft }; //e_el prefixed

////// Basic functions

      bool hasE_TraversalStatus(unsigned char chStat, E_TraversalStat e_tsStat);

      void resetTraverse(E_TraversalType e_ttType);

      CTTreeNode<Type>* getNodeInOrder(void);
      CTTreeNode<Type>* getNodePreOrder(void);
      CTTreeNode<Type>* getNodePostOrder(void);
      CTTreeNode<Type>* getLeafPreOrder(void);};

////// Constructors

template<class Type>
CTTree<Type>::CTTree()
{      
      this->m_root = new CTTreeNode<Type>();
      this->m_root->m_parent = 0;
      this->m_root->m_leftChild = 0;
      this->m_root->m_rightChild = 0;
      this->m_root->m_iInfo = this->m_root->ROOT | this->m_root->RIGHT_THREAD;
}

///// Destructors

template<class Type>
CTTree<Type>::~CTTree()
{
}

///// Basic Functions

template<class Type>
void CTTree<Type>::resetTraverse(E_TraversalType tType)
{
      switch(tType)
      {
      case this->e_ttInOrder:

            this->m_inOrderTraverser = this->m_root;
            this->m_chInOrderStat = 0;

            break;      

      case this->e_ttPreOrder:      

            this->m_preOrderTraverser = this->m_root;
            this->m_chPreOrderStat = this->e_tsFirstTime;

            break;      

      case this->e_ttPostOrder:

            this->m_postOrderTraverser = this->m_root;
            this->m_chPostOrderStat = 0;

            break;

      case this->e_ttAll:

            this->m_preOrderTraverser = this->m_root;
            this->m_chPreOrderStat = this->e_tsFirstTime;

            this->m_inOrderTraverser = this->m_root;
            this->m_chInOrderStat = 0;

            this->m_postOrderTraverser = this->m_root;
            this->m_chPostOrderStat = 0;

            break;

      default: ;

            break;
      }      
}

template<class Type>
CTTreeNode<Type>* CTTree<Type>::getNodePreOrder(void)
{
      switch(this->m_chPreOrderStat)
      {
      case this->e_tsLeftTraversal:
            
            // Search for leftChild, switch to it and return it ###############################
            
            if(this->m_preOrderTraverser->m_leftChild)
            {
                  // go to traverser's left
                  this->m_preOrderTraverser = this->m_preOrderTraverser->m_leftChild;
                  // return the traverser's address
                  return this->m_preOrderTraverser; // also assures next lines will not be executed
            }
            // shift to RightTraversal
            this->m_chPreOrderStat = this->e_tsRightTraveral;
            // intentionally no "break;" to make things go on
            // break;

      case this->e_tsRightTraveral:

            // Search for rightChild ##########################################################

            if(      !this->m_preOrderTraverser->m_rightChild )
            {
                  this->m_chPreOrderStat = this->e_tsFinished;
                  break;
            }
            // while traverser's rightChild IS a thread
            while(this->m_preOrderTraverser->isInfoAKindOf(this->m_preOrderTraverser->RIGHT_THREAD))
            { // find the thread pointing to node with rightChild                  
                        this->m_preOrderTraverser = this->m_preOrderTraverser->m_rightChild;
            }

            // go to traverser's right which is NOT anymore a thread
            this->m_preOrderTraverser = this->m_preOrderTraverser->m_rightChild;

            // check if leftChild exise_ts
            if(this->m_preOrderTraverser->m_leftChild)
            {
                  // Switch mode then;
                  this->m_chPreOrderStat = this->e_tsLeftTraversal;
            }                  
            // return the traverser's address
            return this->m_preOrderTraverser;

      case this->e_tsFirstTime: // is necessary to output the root            
            this->m_chPreOrderStat = this->e_tsLeftTraversal;
            return this->m_preOrderTraverser;

      case this->e_tsFinished:
            return 0;            

      default: ;      
            break;      
      }      
      return 0;
}

template<class Type>
CTTreeNode<Type>* CTTree<Type>::getNodeInOrder(void)
{
      return 0;
}

template<class Type>
CTTreeNode<Type>* CTTree<Type>::getNodePostOrder(void)
{
      return 0;
}

template<class Type>
CTTreeNode<Type>* CTTree<Type>::getLeafPreOrder(void)
{
      CTTreeNode<Type>* tmpNode;

      for( tmpNode = this->getNodePreOrder(); tmpNode; )
      {
            if(      tmpNode->isInfoAKindOf(tmpNode->RIGHT_THREAD) && // no rightChild
                  !tmpNode->m_leftChild )                                          // no leftChild                              
            {
                  return tmpNode;
            }
            tmpNode = this->getNodePreOrder();
      }
      return 0;
}

that is one of those classes... my system is quite large so i can't put it all here..
Thanks again AlexFM.
This is enough. It's impossible to export these classes from Dll. These classes should be supplied in h-files with full implementation code. Client (other programmer which uses these templates for instantiation) should have these h-files to compile his code.
ASKER CERTIFIED SOLUTION
Avatar of AlexFM
AlexFM

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks AlexFM for an idea.. but when I tried to include may header files that have codes for my classes, it generates a linker error (LNK2005)

this is my code for my class that generates an error if i tried to include


------------------

#pragma once


using namespace std;

class CTTreeNodeGreater : public greater< CTTreeNode< CSymbol<unsigned char> > >
{
public:
    bool operator () ( CTTreeNode< CSymbol<unsigned char> > *nodeLeft,
                                 CTTreeNode< CSymbol<unsigned char> > *nodeRight );
};

bool CTTreeNodeGreater::operator () ( CTTreeNode< CSymbol<unsigned char> > *nodeLeft,
                                                        CTTreeNode< CSymbol<unsigned char> > *nodeRight )
{            
      if(nodeLeft->m_data.m_iFrequency > nodeRight->m_data.m_iFrequency ) // 1st level
            return true;
      else if(nodeLeft->m_data.m_iFrequency == nodeRight->m_data.m_iFrequency )
      {
            return (nodeLeft->m_data.m_Symbol > nodeRight->m_data.m_Symbol); // 2nd level
      }
      else
            return false;      
}

--------------- end of header file

the error code is:

"error LNK2005: "public: bool __thiscall CTTreeNodeGreater::operator()(class CTTreeNode<class CSymbol<unsigned char> > *, class CTTreeNode<class CSymbol<unsigned char> > *)(??RCTTreeNodeGreater@@QAE_NPAV?$CTTreeNode@V?$CSymobl@E@@@@0@Z) already defined in frmMain.obj

that's a super long error code :(
NOTE: no copy paste operation it may have some typos in there
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
you're the man! great! it worked! hehe but that's weird.. I don't have to make it inline when it was on VS6.0. By the way thanks! But one last question, how about those static const members? e.g.:

struct CMyclass
{
       static const float m_fData;
};

const float CArchiverHeader::m_fData = 1.0000;

now this one generates two error, one is just the same as the above (LNK2005) and a LNK1169

Thanks a lot AlexFM
const float CArchiverHeader::m_fData = 1.0000;

This line should be placed in one cpp file in the project. Don't place it in h-file.
actually, at first I tried including my class to frmMain.h and it generates an error.

Incidentally, I re-organized my codes and put my include declaration under  stdafx.h
and the error is gone. So there's no really need for seperating it to a cpp file.

But why is this happening?
What's wrong with my headers being included in frmMain.h instead in stdafx.h?

Just want to clear it up why
im asking to much hehe so here's the increase
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
now im confused :( i put back my header declaration to frmMain.h and its now working.. i dont know what i did to make it work, but it works without seperating the static const members to another cpp file.

By the ways thanks AlexFM =)
If the line
const float CArchiverHeader::m_fData = 1.0000;
is part of h-file, it may work if this h-file is included to one cpp file in the project. But if you include this h-file to two or more cpp files, you get linker error "Variable is already defined in...".
can't the "#pragma once" prevent it from being included in two or more cpp files?
#pragma once prevents h-file to be included twice into the same cpp file.
AlexFM, I got some related question please follow this link, I know you could help me there =)
https://www.experts-exchange.com/questions/21222458/STL-in-class-library-project-DLL.html