我有一些模板代码,我宁愿存储在一个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中使用这段代码,但我想移植到其他环境中。


当前回答

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

//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函数,建议使用前面的例子。

其他回答

你举的例子没有问题。但是我必须说,我认为在cpp文件中存储函数定义是不有效的。我只理解需要将函数的声明和定义分开。

当与显式类实例化一起使用时,Boost Concept Check Library (BCCL)可以帮助您在cpp文件中生成模板函数代码。

对于本页上的其他人来说,想知道显式模板专门化(至少在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>;

以上都不适合我,所以这里是如何解决它,我的类只有1个方法模板..

.h

class Model
{
    template <class T>
    void build(T* b, uint32_t number);
};

.cpp

#include "Model.h"
template <class T>
void Model::build(T* b, uint32_t number)
{
    //implementation
}

void TemporaryFunction()
{
    Model m;
    m.build<B1>(new B1(),1);
    m.build<B2>(new B2(), 1);
    m.build<B3>(new B3(), 1);
}

这样可以避免链接错误,并且根本不需要调用TemporaryFunction

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 :).

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

//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函数,建议使用前面的例子。