2

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


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>;

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

4

2 回答 2

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();
}

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

于 2012-07-14T18:53:37.597 回答
1

执行以下操作:

  1. 将定义移动Foo<T>::DoIt()到名为 ImplDoIt.h 的头文件中(不一定与 decl.h 在同一目录中)
  2. 相同的Foo<T>::RemoveIt()- ImplRemoveIt.h
  3. 在您的 impl.cpp 中包含所有这些头文件并实例化模板。
于 2012-07-14T20:16:55.950 回答