多个源中的模板实现

时间:2012-07-14 18:35:50

标签: c++ templates header-files code-cleanup multiple-definition-error

我使用以下模式将模板声明和实现分开:


decl.h(声明)

template <typename T>
struct Foo
{
  void DoIt();
}

impl.cpp(实施)

template <typename T>
void Foo<T>::DoIt() { // impl code 
};

template class Foo<int>;
template class Foo<float>;

现在我想为Foo添加一个新方法,但是impl.cpp文件已经很大了,所以我想把它移到另一个文件impl2.cpp;


decl.h(声明)

template <typename T>
struct Foo
{
  void DoIt();
  void RemoveIt();
}

impl.cpp(实施)

template <typename T>
void Foo<T>::DoIt() { // impl code 
};

template class Foo<int>;
template class Foo<float>;

impl2.cpp(实施)

template <typename T>
void Foo<T>::RemoveIt() { // impl code 
};

template class Foo<int>;
template class Foo<float>;

这里主要关注的是重复的实例化,我该如何避免这些?

2 个答案:

答案 0 :(得分:1)

您需要将常规模板参数T的实现包含在标头中,并在源文件中包含intfloat的显式实例化。

// decl.h
template <typename T>
struct Foo
{
  void DoIt();
  void RemoveIt();
}

#include "impl1.ipp"
#include "impl2.ipp"

// impl1.ipp
template <typename T>
void Foo<T>::DoIt() { // impl code 
};

// impl2.ipp
template <typename T>
void Foo<T>::RemoveIt() { // impl code 
};

// inst.cpp
#include "decl.h"
template class Foo<int>;   // explicit instantiation goes in source file
template class Foo<float>; // explicit instantiation goes in source file

// main.cpp
#include "decl.h"

int main()
{
    // call with concrete template arguments
    Foo<int>::DoIt();
    Foo<float>::RemoveIt();
}

为什么呢?因为DoItRemoveIt是函数模板,而不是函数,并且在看到传递给它们的模板T之前无法编译它们。因此Foo的所有客户端不仅需要包含您的标头,还需要包含您的实施文件。最方便的方法是让标题包含实现。这就是我将它们重命名为.ipp的原因。

答案 1 :(得分:1)

请执行以下操作:

  1. Foo<T>::DoIt()的定义移至名为的某个头文件 ImplDoIt.h(不一定与decl.h在同一目录中)
  2. Foo<T>::RemoveIt()相同 - ImplRemoveIt.h
  3. 在impl.cpp中包含所有这些头文件并实例化模板。