Solved

C++ Templates in library; how to link?

Posted on 1997-12-08
10
2,057 Views
Last Modified: 2013-12-14
I have in a static library C++ class template. In an application I am trying to link with that library, I am getting unresolved errors with a particular instance of this template. I figured it was becuase this template was not being instantiated in the library and so it couldn't find the proper code in the library to link with.

I checked the online help of MSVC++5.0 and found that you need to 'explicitly instantiate' the template to work. So, I tried it. And what I have does not work.

I have 2 class templates, and made a .cpp file to instantiate both of them to the relevant types, and included whats shown below.

template  CuListNode<CuChoice>;
template  CuList<CuChoice>;

I get warnings of : no suitable definition provided for explicit template instantiation request for each member function and constructor/destructor in the templates file.


And I get unresolved external symbol errors as such:
 CuList<class CuChoice>::CuList<class CuChoice>(void)(??0?$CuList@VCuChoice@@@@QAE@XZ)

How should I work this out, and what possibly am I doing wrong with the instantiation? I know its a moutful, but I hope someone can help.

Thanks a lot.

Tom
0
Comment
Question by:gunn
10 Comments
 
LVL 2

Expert Comment

by:mitchell042997
Comment Utility
OK, are you sure you are using templates correctly?

First, in your class defintion, you need to use the template statement.  So, say we are making a class which will do arithmetic operations on numbers.  The numbers could be a float, int, etc.  This is an example of when to use templates, because the actual function code won't be determined until run-time.

So, first, to define our class:

template<class NumType>
class Number {
private:
  NumType data;

public:
  MixedMath();
  ~MixedMath();

  NumType Add(int someInt);
};

Now, your function code must look like this!

template<class NumType>
Number<NumType>::Number()
{  // do constructor business
}

template<class NumType>
Number<NumType>::~Number()
{  // do destructor business
}

template<class NumType>
NumType Number<NumType>::Add(int someNumber)
{
  return data+(NumType)someNumber
}

So see, you need the template<class ...> and then the class name for the template in the class name before the ::.

Then, in your main program, when you create an instantiation of the Number class, you need to define its type.  For example, if you wanted to make it a double, you'd do:

int main() {
  Number<double> myNumber;
...


Does that answer your question?  Happy Programming!
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
Yes, nietod, that is exactly what I am trying to do. The template definition is buried in a static library I have made. My executable file has nothing to do directly with the templates, but when I link with this library, I get the unresolved errors towards that specific type.

Any fix?
0
 

Author Comment

by:gunn
Comment Utility
I checked the code against what mitchell had said, and its good. The problem has to do excactly as nietod said. The code is an a static library I created, so it doesn't know before-hand how to instantiate itself. I've tried to do it as they say, 'explicitly' but it doesn't seem to work. The .cpp file in the library I'm using to explicitly declare looks like :


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

#include "CuList.h"

#include "CuListNode.h"

#include "CuChoice.h"





template class CuListNode<CuChoice>;

template class  CuList<CuChoice>;
-------

but that doesn't seem to do it, as I get the same linker errors + compile warnings like below for each member function:

D:CuTemplates.cpp(11) : warning C4661: 'CuListNode<class CuChoice>::CuListNode<class CuChoice>(const class CuChoice)' : no suitable definition provided for explicit template instantiation request

And the two 'exact' linker errors like (libCXm.lib is my static library):

libCXm.lib(CXmChoiceMenu.obj) : error LNK2001: unresolved external symbol "public: __thiscall CuList<class CuChoice>::CuList<class CuChoice>(void)" (??0?$CuList@VCuChoice@@@@QAE@XZ)

libCXm.lib(CXmChoiceMenu.obj) : error LNK2001: unresolved external symbol "public: virtual __thiscall CuList<class CuChoice>::~CuList<class CuChoice>(void)" (??1?$CuList@VCuChoice@@@@UAE@XZ)

Does that info help any?


0
 

Author Comment

by:gunn
Comment Utility
I have a way to do this for dynamic libraries (DLL's) that works, and should work for a static library.   I don't know that it the best way, I just know that it works, so I'm posting this as a comment in case someone can give you beter advice.

What I do, is in the library create a non-template class that is a derived from the template class instantiated for a particular type.  That's clear isn't it?  an example.  

(the syntax may not be 100% correct, but this should give you the idea)  Say you have an array template class, called Array.  Yo can create two non-template clases one for characters and one for integers as follows.  These clases could be made exportable as appropriate (extern in you case, DllExp in mine)

template <class T> class Array
{
// stuff
};

class IntArray  : public Array<int>;
class CharArray : public Array<char>;

Does that help?
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
Well, I tried that nietod. The sample file compiled file, but I got the same linker problems, just with that file instead.

I'm stumped. It seems that being in a static library, that particular type doesn't get instantiated, and is then not able to during linking to make an executable.

Theres some info on 'Explicit Instantiation" and a word about templates in libraries in the MSVC++ online help, but I can't get what they have in there to work, which is kind of what I have in my original question.

I'm stumped! Theres got to be someone who uses templates in libraries and gets them to work!! ahhhhhhhh

0
Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

 

Author Comment

by:gunn
Comment Utility
Where (when) do you get the errors?  When compiling the static library or the program that uses it?

Stupid question but.. You did change the program that uses the static library so it now uses the derived classes and not the template classes.  Right?


0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
Post your current code if you can.
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
I do two things to make this work:

First, create two separate header files for the template class.  One contains the declaration of the template class and its members.  The other contains the *definitions* of the template class members.  It is desirable to separate these so that only the static library sees the member definitions.  Consider the trival template class A declared in "templ.h":

///////////////////////////////////////////////////
// templ.h:  Define a trivial template class
template <class T> class A {
public:
      A();
      ~A();
      T f(T t);
      T m_t;
};
///////////////////////////////////////////////////


... and a definition of its members in templ_def.h:
///////////////////////////////////////////////////
// templ_def.h: Definition of template members, only for library
template <class T> inline A<T>::A() {}
template <class T> inline A<T>::~A() {}
template <class T> inline T A<T>::f(T t) { return t; }
///////////////////////////////////////////////////

... the static library source file "templ.cpp" includes both these headers and explicitly instantiates the template and its members.  templ.cpp is compiled and built into the static library:

///////////////////////////////////////////////////
// templ.cpp:  Instantiate the template for a static library
#include "templ.h"      // Include the template definition
#include "templ_def.h"  // Include member definitions
// Explicitly instantiate the template and its members
template class A<int>;
///////////////////////////////////////////////////

... finally, "use_templ.cpp" includes only the template declaration, but not the member definitions, and links with the library to get the compiled member functions:

///////////////////////////////////////////////////
// use_templ.cpp: Use the template instance defined
// in the static library by templ.cpp
#include "stdio.h"
#include "templ.h"  // Include the template declaration
// ... but don't include the member definitions in templ_def.h
// that prevents this file from "accidentally" instantiating
// a copy of the members

// Instantiate the template without members
// Members should be linked from the library
extern template class A<int>;

void main()
{
      A<int> a;
      printf("A<int>::f(3) == %d\n", a.f(3));
}
///////////////////////////////////////////////////

0
 

Accepted Solution

by:
jlilley earned 100 total points
Comment Utility
Yoooohooo!

That was it! I changed the *.cpp files of my templates to *_def.h with the definitions and made them inline, and made up a new *_inst.cpp to instantiate the class and built it into the static library. Worked like a charm, no compiler errors...nothing.

Then, linked with my application and walla! No linker error for that anymore....I'm a happy guy now...thanks a lot for everyone's help...especially jlilly! (now, if i can get through these other probs..heheheh, one step at a time.)

Thanks,

Tom

0
 

Author Comment

by:gunn
Comment Utility
Yoooohooo!

That was it! I changed the *.cpp files of my templates to *_def.h with the definitions and made them inline, and made up a new *_inst.cpp to instantiate the class and built it into the static library. Worked like a charm, no compiler errors...nothing.

Then, linked with my application and walla! No linker error for that anymore....I'm a happy guy now...thanks a lot for everyone's help...especially jlilly! (now, if i can get through these other probs..heheheh, one step at a time.)

Thanks,

Tom

0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

This article will show you some of the more useful Standard Template Library (STL) algorithms through the use of working examples.  You will learn about how these algorithms fit into the STL architecture, how they work with STL containers, and why t…
Update (December 2011): Since this article was published, the things have changed for good for Android native developers. The Sequoyah Project (http://www.eclipse.org/sequoyah/) automates most of the tasks discussed in this article. You can even fin…
The viewer will learn how to use and create keystrokes in Netbeans IDE 8.0 for Windows.
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

771 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now