我有一些模板代码,我宁愿存储在一个CPP文件,而不是内联在头。我知道这是可以做到的,只要您知道将使用哪种模板类型。例如:

. h文件

class foo
{
public:
    template <typename T>
    void do(const T& t);
};

. cpp文件

template <typename T>
void foo::do(const T& t)
{
    // Do something with t
}

template void foo::do<int>(const int&);
template void foo::do<std::string>(const std::string&);

注意最后两行- foo::do模板函数只用于int和std::string,所以这些定义意味着应用程序将链接。

我的问题是-这是一个讨厌的黑客或这将与其他编译器/链接器工作吗?目前我只在VS2008中使用这段代码,但我想移植到其他环境中。


当前回答

对于本页上的其他人来说,想知道显式模板专门化(至少在VS2008中)的正确语法是什么(和我一样),它如下…

在你的.h文件中…

template<typename T>
class foo
{
public:
    void bar(const T &t);
};

在你的。cpp文件中

template <class T>
void foo<T>::bar(const T &t)
{ }

// Explicit template instantiation
template class foo<int>;

其他回答

您描述的问题可以通过在头文件中定义模板来解决,也可以通过上面描述的方法来解决。

我推荐阅读c++ FAQ Lite中的以下几点:

为什么我不能将模板类的定义与其声明分开,并将其放入.cpp文件中? 我如何避免链接错误与我的模板函数? c++关键字导出如何帮助处理模板链接器错误?

它们详细讨论了这些(和其他)模板问题。

让我们举一个例子,假设出于某种原因你想要一个模板类:

//test_template.h:
#pragma once
#include <cstdio>

template <class T>
class DemoT
{
public:
    void test()
    {
        printf("ok\n");
    }
};

template <>
void DemoT<int>::test()
{
    printf("int test (int)\n");
}


template <>
void DemoT<bool>::test()
{
    printf("int test (bool)\n");
}

如果你用Visual Studio编译这段代码,它可以开箱即用。 GCC将产生链接器错误(如果从多个.cpp文件中使用相同的头文件):

error : multiple definition of `DemoT<int>::test()'; your.o: .../test_template.h:16: first defined here

可以将实现移动到.cpp文件,但随后需要像这样声明类-

//test_template.h:
#pragma once
#include <cstdio>

template <class T>
class DemoT
{
public:
    void test()
    {
        printf("ok\n");
    }
};

template <>
void DemoT<int>::test();

template <>
void DemoT<bool>::test();

// Instantiate parametrized template classes, implementation resides on .cpp side.
template class DemoT<bool>;
template class DemoT<int>;

然后。cpp看起来是这样的:

//test_template.cpp:
#include "test_template.h"

template <>
void DemoT<int>::test()
{
    printf("int test (int)\n");
}


template <>
void DemoT<bool>::test()
{
    printf("int test (bool)\n");
}

如果头文件中没有最后两行- gcc可以正常工作,但是Visual studio会产生一个错误:

 error LNK2019: unresolved external symbol "public: void __cdecl DemoT<int>::test(void)" (?test@?$DemoT@H@@QEAAXXZ) referenced in function

如果你想通过.dll导出来公开函数,模板类语法是可选的,但这只适用于Windows平台-所以test_template.h可以像这样:

//test_template.h:
#pragma once
#include <cstdio>

template <class T>
class DemoT
{
public:
    void test()
    {
        printf("ok\n");
    }
};

#ifdef _WIN32
    #define DLL_EXPORT __declspec(dllexport) 
#else
    #define DLL_EXPORT
#endif

template <>
void DLL_EXPORT DemoT<int>::test();

template <>
void DLL_EXPORT DemoT<bool>::test();

使用前面示例中的.cpp文件。

然而,这给链接器带来了更多的头痛,所以如果你不导出.dll函数,建议使用前面的例子。

对于本页上的其他人来说,想知道显式模板专门化(至少在VS2008中)的正确语法是什么(和我一样),它如下…

在你的.h文件中…

template<typename T>
class foo
{
public:
    void bar(const T &t);
};

在你的。cpp文件中

template <class T>
void foo<T>::bar(const T &t)
{ }

// Explicit template instantiation
template class foo<int>;

这应该在支持模板的任何地方都能正常工作。显式模板实例化是c++标准的一部分。

This is definitely not a nasty hack, but be aware of the fact that you will have to do it (the explicit template specialization) for every class/type you want to use with the given template. In case of MANY types requesting template instantiation there can be A LOT of lines in your .cpp file. To remedy this problem you can have a TemplateClassInst.cpp in every project you use so that you have greater control what types will be instantiated. Obviously this solution will not be perfect (aka silver bullet) as you might end up breaking the ODR :).