• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 348
  • Last Modified:

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.
0
anthon007r
Asked:
anthon007r
  • 9
  • 9
3 Solutions
 
AlexFMCommented:
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
0
 
anthon007rAuthor Commented:
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.
0
 
AlexFMCommented:
Please show some code fragments, what classes do you want to export from Dll?
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
anthon007rAuthor Commented:
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.
0
 
AlexFMCommented:
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.
0
 
AlexFMCommented:
BTW, are you talking about exposing of these classes to managed client? It's impossible because managed client cannot instantiate templates (at least, in VS 2003). However, if you want to expose template instantiation to managed client, you can write managed wrapper for this.

class __gc IntegerTreeWrapper
{
public:
   // wrapper methods for m_tree member
   // ..
   
   private:
       CTTree<int> m_tree;
};
0
 
anthon007rAuthor Commented:
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
0
 
AlexFMCommented:
All template class member function should be defined inside of class, or after class definition, in the same h-file with inline keyword. Your choices:

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

or:

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

// add inline keyword:
inline bool CTTreeNodeGreater::operator () ( CTTreeNode< CSymbol<unsigned char> > *nodeLeft,
                                               CTTreeNode< CSymbol<unsigned char> > *nodeRight )
{          
  ...  
}
0
 
anthon007rAuthor Commented:
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
0
 
AlexFMCommented:
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.
0
 
anthon007rAuthor Commented:
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
0
 
anthon007rAuthor Commented:
im asking to much hehe so here's the increase
0
 
AlexFMCommented:
General rule is that every variable or function should be defined (implemented) in only one cpp file. To use it in other cpp file, compiler needs only it's declaration.

Example 1.

// file1.cpp

int x;

// file2.cpp

int x;

Result is linker error: symbol ...x... already defined in ...

Example 2.

// file1.cpp

int x;

// file2.cpp

extern int x;

This program compiles and links successfully.

Example 3.

// x.h
int x;

// file1.cpp
#include "x.h"

// file2.cpp
#include "x.h"

Linker error, as in example 1.

Example 4.

// x.h
extern int x;

// file1.cpp
#include "x.h"

int x;

// file2.cpp
#include "x.h"

OK.

The same rules are applied to functions and static class members. Function is declared in h-file, but should be implemented only once.

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

This happened because function was implemented in every cpp file where h-file was included. Adding inline keyword removes all implementations of this function, so linker is happy.

Static class member is declared in h-file:

struct CMyclass
{
       static const float m_fData;
};

It is client responsibility to define (implement) it in one cpp file:
const float CArchiverHeader::m_fData = 1.0000;

I don't know what happens in your project now, I need to see code fragments to be more specific.
0
 
anthon007rAuthor Commented:
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 =)
0
 
AlexFMCommented:
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...".
0
 
anthon007rAuthor Commented:
can't the "#pragma once" prevent it from being included in two or more cpp files?
0
 
AlexFMCommented:
#pragma once prevents h-file to be included twice into the same cpp file.
0
 
anthon007rAuthor Commented:
AlexFM, I got some related question please follow this link, I know you could help me there =)
http://www.experts-exchange.com/Programming/Programming_Languages/Dot_Net/VisualC_PLUS_PLUS_DOT_NET/Q_21222458.html
0

Featured Post

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

  • 9
  • 9
Tackle projects and never again get stuck behind a technical roadblock.
Join Now