Solved

C++ Templates in library; how to link?

Posted on 1997-12-08
10
2,124 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
10 Comments
 
LVL 2

Expert Comment

by:mitchell042997
ID: 1175242
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
ID: 1175243
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
ID: 1175244
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
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:gunn
ID: 1175245
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
ID: 1175246
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
 

Author Comment

by:gunn
ID: 1175247
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
ID: 1175248
Post your current code if you can.
0
 
LVL 22

Expert Comment

by:nietod
ID: 1175249
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
ID: 1175250
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
ID: 1175251
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

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

IntroductionThis article is the second in a three part article series on the Visual Studio 2008 Debugger.  It provides tips in setting and using breakpoints. If not familiar with this debugger, you can find a basic introduction in the EE article loc…
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
The viewer will learn how to use and create keystrokes in Netbeans IDE 8.0 for Windows.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

696 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