模板静态库与模板实例化

时间:2013-02-26 01:07:06

标签: c++ templates

我正在开发一个静态库,该库有多个类模板和函数模板。我理解为了使用静态库中的模板,所有(声明/定义)都需要在头文件中。但是,在这种特殊情况下,因为我知道我认为可以使用的特化类型转发声明专门化。

这个技巧与类模板(及其函数)很好地配合,我可以使用我的应用程序代码中的所有库函数。但是,只要我在库中引入自由函数模板并尝试使用我的应用程序代码中的免费模板化函数,它就会给我链接器错误:

  

错误LNK2019:未解析的外部符号“类   TemplatedStaticLib __cdecl HelpingRegistration(int)“   (?? $ HelpingRegistration 3 H @@ YA?AV?$ TemplatedStaticLib 3 H @@ H + Z)   在函数_main中引用   1 GT; C:\ SRC \ CPP \ VS2008 \ StaticLibExample \ MathFuncsLib \调试\ TemplatedStaticLibApp.exe   :致命错误LNK1120:1个未解析的外部“   我正在使用VS2008,这里是代码

//静态库头文件(.h)

#ifndef _TEMPLATED_STATIC_LIB_
#define _TEMPLATED_STATIC_LIB_

#include <iostream>

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

    void print(T t);

};

template<typename T>
TemplatedStaticLib<T> HelpingRegistration(T);


#endif

//静态库类文件(.cpp)

#include "TemplatedStaticLib.h"

//Specialization
template class TemplatedStaticLib<double>;
template class TemplatedStaticLib<int>;
template class TemplatedStaticLib<std::string>;


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

void HelpingRegistration(void)
{
}

//Specialization of free function
template<> TemplatedStaticLib<int> HelpingRegistration<int>(int);
template<> TemplatedStaticLib<double> HelpingRegistration<double>(double);
template<> TemplatedStaticLib<std::string> HelpingRegistration<std::string>(std::string);

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

//应用程序代码

#include "TemplatedStaticLib.h"

int main(int argc, char* argv[])
{
    int anInt = 99;
    TemplatedStaticLib<int> test; 
    test.print(anInt);//works

    double aDouble = 3.9;
    TemplatedStaticLib<double> double_test; 
    double_test.print(aDouble); //works

    std::string aString = "James";

    TemplatedStaticLib<std::string> string_test; 
    string_test.print(aString);//works

    //The following lines gives linker error
    HelpingRegistration(anInt);
    HelpingRegistration(aDouble);
    HelpingRegistration(aString);


    return 0;
}

我不确定为什么会有所不同以及如何解决这个问题。任何帮助表示赞赏。

1 个答案:

答案 0 :(得分:9)

请注意,这些是前向声明,而是类模板的显式实例化。这就是允许您将定义放在.cpp文件中并且链接器不会得到任何未解析的引用错误的原因,只要在其他转换单元中您只使用这些模板实例化。

另一方面,这些:

template<> TemplatedStaticLib<int> HelpingRegistration<int>(int);
template<> TemplatedStaticLib<double> HelpingRegistration<double>(double);
template<> TemplatedStaticLib<std::string> HelpingRegistration<std::string>(std::string);

是函数模板的显式特化的声明。相反,您最想要做的是提供显式实例化。这样做的语法如下:

template TemplatedStaticLib<int> HelpingRegistration<>(int);
template TemplatedStaticLib<double> HelpingRegistration<>(double);
template TemplatedStaticLib<std::string> HelpingRegistration<>(std::string);

一旦你解决了这个问题,你会发现编译器实际上会实例化你的HelpingRegistration<>()函数模板,并且这样做时也会发出错误,因为你正试图将int(分别为doublestring)转换为TemplatedStaticLib<int>类型的对象(分别为TemplatedStaticLib<double>TemplatedStaticLib<string>),没有提供转换(或者至少没有在您发布的代码中显示):

template<typename T>
TemplatedStaticLib<T> HelpingRegistration(T t)
{
    std::cout << "Function Templated Print "  << typeid(t).name() << std::endl;
    return t; // CANNOT BE CONVERTED!
}

修复此错误(例如通过执行return TemplateStaticLib<T>();)将使程序编译链接。