6

I am using VS2008 in win7 and g++ 4.7 in CentOS 18. The issue is only seen on Windows when I used dynamically shared library. When I convert it static library the program links fine.

I understand that in shared library template functions/class either should be defined in header file or template instantiation of the template types(parameters) should be provided through compilation unit. I have chosen the later option. I have done it before, I went through

Why can templates only be implemented in the header file?

C++ Shared Library with Templates: Undefined symbols error

But I cannot figure out why in windows as soon as I convert the library to dll it failed to resolve symbols: error LNK2019: unresolved external symbol "void __cdecl HelpingRegistration(double)" (??$HelpingRegistration@N@@YAXN@Z) referenced in function _main

In Windows it works fine with static library. In Linux both dynamic and shared library works.

//Static library
//Library header
#ifndef _TEMPLATED_STATIC_LIB_
#define _TEMPLATED_STATIC_LIB_

#include <iostream>
#include <string>
#include "Export.h"

template<typename T>
class EXPORT TemplatedStaticLib
{
public:
    TemplatedStaticLib(){};
    ~TemplatedStaticLib(){};

    void print(T t);

};

template<typename T>
EXPORT void HelpingRegistration(T);

#endif

//library .cpp

#include "TemplatedStaticLib.h"
#include <typeinfo>


template<typename T>
void TemplatedStaticLib<T>::print(T t)
{
    std::cout << "Templated Print: "<< t<< " type:: "  << typeid(t).name() << std::endl;
}

//Class Template explicit instantiation
template class TemplatedStaticLib<double>;
template class TemplatedStaticLib<std::string>;

template<typename T>
void  HelpingRegistration(T t)
{
    std::cout << "Function Templated Print: "  << t << " type: " << typeid(t).name() << std::endl;
       //return t;
}

//function template explicit instantiation
template void HelpingRegistration<>( double );
template void HelpingRegistration<>( std::string );

//Windows symbol exporter

//.h

#ifndef STATIC_LIB_EXPORT
#define STATIC_LIB_EXPORT

#if !defined WIN32
    #define EXPORT
#elif defined LIB_EXPORTS
    #define EXPORT __declspec(dllexport)
#else
    #define EXPORT __declspec(dllimport)
#endif

//STATIC_LIB_EXPORT
#endif

//library user .cpp

#include <TemplatedStaticLib/TemplatedStaticLib.h>

#include<string>

int main(int argc, char* argv[])
{
    double aDouble = 3.9;
    TemplatedStaticLib<double> double_test; 
    double_test.print(aDouble);

    std::string aString = "James";
    TemplatedStaticLib<std::string> string_test; 
    string_test.print(aString);

    HelpingRegistration(aDouble);
    HelpingRegistration(aString);


    return 0;
}
Community
  • 1
  • 1
jazaman
  • 1,007
  • 3
  • 12
  • 30
  • There are literary thousands of duplicates to this one. You can't split templated classes into header and source file like usual, it all have to be in the headers. – Some programmer dude Jul 08 '13 at 05:50
  • possible duplicate of [Why can templates only be implemented in the header file?](http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file) – juanchopanza Jul 08 '13 at 05:51
  • @Joachim Pileborg it definitely can be done as shown in the answer provide in the question http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file and I am doing this too only in Windows dll it causing issuee pleae read the full question first – jazaman Jul 08 '13 at 05:54
  • @juanchopanza the link you provided doesn't explain why only on shared dll it's causing problem – jazaman Jul 08 '13 at 05:55
  • It doesn't explain why it "only" causes problems in a DLL, but it explains *why* it causes those problems. You should be asking why something broken seems to work in a static library. Actually, you shouldn't be trying to use broken code. – juanchopanza Jul 08 '13 at 05:57
  • @juanchopanza I went through the links you provided and it does suggest if an explicit instantiation is provided, it should work and it does with g++ compiler. It's ok if you do not know vs2008 specific answer but why mark down, other people may know the answer. – jazaman Jul 08 '13 at 06:03

3 Answers3

4

I believe you need to export the specializations. Have you tried this in your .cpp file:

template class EXPORT TemplatedStaticLib<double>;
template class EXPORT TemplatedStaticLib<std::string>;

and pretty much the same in your header:

template class EXPORT TemplateStaticLib<double>;
template class EXPORT TemplateStaticLib<std::string>;

I think that will work with your EXPORT macro (assuming the .cpp file see __declspec(dllexport) and the header sees __declspec(dllimport)). I admit I'm not an expert with Windows' __declspec.

I admit that I drew my answer from this other answer on the intarwebs: http://social.msdn.microsoft.com/Forums/vstudio/en-US/4fd49664-e28e-4f23-b1eb-b669d35ad264/function-template-instantation-export-from-dll (scroll all the way to the bottom for Franjo555's final version.)

Violet Giraffe
  • 32,368
  • 48
  • 194
  • 335
Joe Z
  • 17,413
  • 3
  • 28
  • 39
  • The class template symbols are present. But the free function template symbols are missing. I used dumpbin /EXPORT to see the symbols. I worked out solution which I am going to post next. – jazaman Jul 08 '13 at 12:42
  • Your idea was right though I needed to export the function template instantiations ... thanks – jazaman Jul 08 '13 at 12:57
  • You don't need to `__declspec(dllimport)` the methods, assuming that the class itself is exported / imported. – Mark Ingram Jan 17 '14 at 14:11
  • Note that `EXPORT` here should be after `class`, not before it. If it's before it, no exports are generated. – porges Jan 10 '17 at 23:11
  • Please note that the exported specialization of te template class in the .cpp file must appear *before* any specialized method, not after. Tested on VS2017. – Bentoy13 Jan 11 '19 at 14:44
3

I worked out the problem. Under windows class template and function template are exported differently and there is a interesting reading on the net.

VS compilers exports class template symbols if class template is instantiated on the translation unit (.cpp).

However, in the case of function template, the keyword '__declspec(dllexport)' needs to be present explicitly for the symbols to be present on the dynamic library.

e.g

template EXPORT void HelpingRegistration<double>( double );
//EXPORT is defined as __declspec(dllexport) 

It's just another case where VS decide to things differently. There is interesting reading here: http://www.codesynthesis.com/~boris/blog/2010/01/18/dll-export-cxx-templates/

jazaman
  • 1,007
  • 3
  • 12
  • 30
0

I believe this is because compiler creates specialized code for template class when the template class is first used with a specific parameters. Since compiler uses only the included header files (.h) when compling a compilation unit (.cpp files) all the tmplate code must be available in .h files. You can export specialized template classes from a dll but not the template classes themselves.