C++ 多文件模板实现
对于普通函数,声明和定义通常在多个文件中分开,如下所示:C++ 多文件模板实现,c++,templates,C++,Templates,对于普通函数,声明和定义通常在多个文件中分开,如下所示: // Foo.h namespace Foo { void Bar(); } //Foo.cpp #包括“Foo.h” void Foo::Bar() { cout您需要在.hxx文件中编写模板化方法的定义,并将其包含在声明它的头文件(.hh)的末尾。使用.cc/.cpp定义非模板化方法 因此,您将有一个.hh、一个.hxx(包含在.hh末尾)和一个.cc;因此,包含模板化类头文件也将包含其定义 例如: // list.hh
// Foo.h
namespace Foo
{
void Bar();
}
//Foo.cpp
#包括“Foo.h”
void Foo::Bar()
{
cout您需要在.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"
// ...
//list.hh
#IFNDEF列表
#定义列表
模板
班级名单
{
void fun1(ta);
void fun2();
}
#包括“list.hxx”
#恩迪夫
//list.hxx
#IFNDEF列表\u HXX
#定义列表\u HXX
#包括“list.hh”
模板
无效列表::fun1(TA)
{
// ...
}
#恩迪夫
//list.cc
#包括“list.hh”
无效列表::fun2()
{
// ...
}
//anywhere.cc
#包括“list.hh”
// ...
编辑
编译模板有几种策略。最常见的策略是上面描述的让类模板的每个用户实例化代码的策略
但是,由于*.hh文件包含*.hxx文件,因此每次需要模板的简单声明时,都会附带完整的实现。如果实现需要其他声明,如std::string,则强制所有客户端代码解析字符串头
为了避免多次实例化(耗费时间和空间),可以引入第四种类型的文件*.hcc:必须为每个具体模板参数编译一次的文件
EDIT2
直接在头文件中写入模板定义称为包含模型。这样做会增加包含头的成本。这不仅是因为我们添加了模板的定义,还因为我们包含了头(,无论什么)这代表了数千行。对于要编译的重要程序来说是一个真正的问题(我们在这里谈论的是编译的时间)。
分离模型
我的最后一个论点是:清除头文件,使其仅包含类声明及其文档。这样,任何其他程序员都可以快速读取头文件:这个类的公共接口是什么,文档说明了什么。模板代码保留在.hh
文件中。没有理由o使它们成为单独的文件,但最好将定义放在所有声明之后
当编译器生成模板代码时,它会对其进行标记,以便链接器知道一个编译单元(即.o
文件)中的模板实例化与另一个单元中的模板实例化是完全相同的代码。它将保留一个模板并丢弃其余的模板,而不是使用“乘法定义符号”错误退出
具有良好模板支持的现代编译器也是如此。在GCC的情况下,从2.8开始(我知道,我为GCC 2.7.2.2编写了很多代码,在他们对链接器进行智能化之前,您必须跳转以正确构建模板)我很失望,没有答案提到C++标准<强>允许>将定义与声明分开。
// Foo.h
export template<class T> T f();
//Foo.h
导出模板tf();
//Foo.cpp
#包括“Foo.h”
导出模板tf()
{
//废话
}
不幸的是,几乎没有编译器支持导出
<>但是,在C++ C++中,导出被从C++中删除。不能把它放在<代码> fo.CPP中,因为它只在创建代码> fo.o>代码>时看到。你可以把它放在<代码> FooSuthnist.H./C>中,它包括“代码> fo.h < /Cord>”,并且被需要模板定义的任何东西所包含,而不是仅仅声明的……所有这些都包括Foo.h
,因此没有必要将它们分开。好消息是,现代链接器可以识别函数是多个.o
文件中模板代码的实例化,并且不会因“多定义”而消亡错误,但会选择一个并将所有内容链接到它。我看不出在.hh
和.hxx
文件之间拆分它们有任何意义,因为如果你拉入一个,你总是会同时得到这两个文件。不妨将它们放在一起。为什么方法可以在单独的文件中定义,而独立的函数却不能?编译器不知道确切的原因在编译代码之前,需要实例化它。另外,C++编译器被设计为不知道项目中的其他源文件;这就是为什么我们有“包含文件”的原因。是的。@Mike DeSimone@Maxpm请看我的编辑,这与编译时间有关optimization@Julio:我还是不明白重点。按照你的设置方式,包括“list.hh”
会让你得到list.hh
,然后是list.hxx
,以及包括“list.hxx”
获取list.hh
后接list.hxx
。所有内容都可能在list.hh
中,您会得到完全相同的结果。我看不出您在编译时优化了什么(通常的“编译时优化”定义),尽管看起来您试图让编译器少编译(即“优化编译时”),但要做到这一点,您需要删除#include“list.hxx”。C++是什么标准?这几乎是禅宗:如果一个标准允许一些聪明的东西,但是编译器不执行它,这个技术是有效的吗?@迈克:问题是它太复杂了,无法用传统的编译器/链接器工具链来实现,所以所有的主要厂商都禁止它。我们有聪明的编译器和哑链接器,应该是这样。另一方面。请注意,传统的编译器不会检查ODR冲突,但这是标准所禁止的(是的,不需要诊断,诸如此类)。谢谢
// Foo.h
export template<class T> T f();
// Foo.cpp
#include "Foo.h"
export template<class T> T f()
{
// blah blah
}