Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
?
Solved

C++ Templates in library; how to link?

Posted on 1997-12-08
10
Medium Priority
?
2,212 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
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 

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 400 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

How to Use the Help Bell

Need to boost the visibility of your question for solutions? Use the Experts Exchange Help Bell to confirm priority levels and contact subject-matter experts for question attention.  Check out this how-to article for more information.

Question has a verified solution.

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

Introduction This article is the first in a series of articles about the C/C++ Visual Studio Express debugger.  It provides a quick start guide in using the debugger. Part 2 focuses on additional topics in breakpoints.  Lastly, Part 3 focuses on th…
Article by: evilrix
Looking for a way to avoid searching through large data sets for data that doesn't exist? A Bloom Filter might be what you need. This data structure is a probabilistic filter that allows you to avoid unnecessary searches when you know the data defin…
The viewer will learn how to use NetBeans IDE 8.0 for Windows to connect to a MySQL database. Open Services Panel: Create a new connection using New Connection Wizard: Create a test database called eetutorial: Create a new test tabel called ee…
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
Suggested Courses

604 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