多文件模板实现

时间:2010-12-21 05:07:26

标签: c++ templates

使用普通函数时,声明和定义通常分隔在多个文件中,如下所示:

// Foo.h

namespace Foo
{
    void Bar();
}

// Foo.cpp

#include "Foo.h"

void Foo::Bar()
{
    cout << "Inside function." << endl;
}

据我了解,无法使用模板完成。声明和定义不能分开,因为模板的适当形式是在需要时“按需”创建的。

那么,模板通常如何以及在何处定义在这样的多文件项目中?我的直觉是它会在Foo.cpp中,因为这是函数的“肉”通常所在,但另一方面它是将包含的头文件。

3 个答案:

答案 0 :(得分:4)

您需要在.hxx文件中编写模板化方法的定义,并将其包含在您声明它的头文件(.hh)的末尾。 .cc / .cpp用于定义非模板化方法。

所以你将有一个.hh,一个.hxx(包括在.hh的末尾)和一个.cc;因此,包含模板化类头文件也将包含其定义。

示例:

// list.hh
#IFNDEF LIST_HH
# DEFINE LIST_HH

template <typename T>
class List
{
  void fun1(T a);

  void fun2();
}

# include "list.hxx"

#ENDIF

// list.hxx
#IFNDEF LIST_HXX
# DEFINE LIST_HXX

# include "list.hh"

template <typename T>
void List::fun1(T a)
{
   // ...
}

#ENDIF

// list.cc

#include "list.hh"

void List::fun2()
{
   // ...
}


// anywhere.cc

#include "list.hh"

// ...

修改

编译模板有几种策略。最常见的策略是上面描述的策略,让类模板的每个用户实例化代码。

但是,因为* .hh文件包含* .hxx文件,所以每次需要简单的模板声明时,都会附带完整的实现。如果实现需要其他声明,例如std :: string,则强制所有客户端代码解析字符串头。

为避免多次实例化(耗费时间和空间),您可以引入第四种类型的文件* .hcc:必须为每个具体模板参数编译一次的文件。

See Also Compile-Time Dependencies

<强> EDIT2

直接在头文件中编写模板定义称为包含模型。这样做会增加包含标题的成本。不仅因为我们添加了模板的定义,还因为我们包含代表数千行的标题(,等等)。 重要程序编译的一个真正问题(我们在这里谈论编译时间)分离模型

Source

我的最后一个论点:清除头文件,使其只包含类声明及其文档。像这样,任何其他程序员都能够快速读取你的头文件:这个类的公共接口是什么,文档说的是什么。

答案 1 :(得分:2)

模板代码保留在.hh文件中。没有理由将它们作为单独的文件,尽管将这些定义放在 all 声明之后是个好习惯。

当编译器生成模板代码时,它会对其进行标记,以便链接器知道一个编译单元(即.o文件)中模板的实例化与另一个单元中的模板完全相同。它将保留一个并丢弃其余的,而不是用“多重定义的符号”错误挽救。

具有良好模板支持的现代编译器也是如此。在海湾合作委员会的情况下,自2.8。 (我知道,我在gcc 2.7.2.2上编写了很多代码,然后才开始使用链接器,你必须跳过箍来使模板构建正确。)

答案 2 :(得分:2)

我很失望没有回答提到C ++标准允许你将定义与声明分开。它是这样的:

// Foo.h
export template<class T> T f();

// Foo.cpp
#include "Foo.h"

export template<class T> T f()
{
    // blah blah
}

不幸的是,几乎没有编译器支持 export 。 Comeau就是其中之一。

但是, export 将从C ++ 0x中的C ++中删除。