看着这个项目(http://www.savarese.com/software/libssrckdtree/),我找到了“C++ header-only template library”的定义。目前我有基本的 C++ 知识,但想知道这到底意味着什么以及为什么这个人在这个项目中使用它
9 回答
这意味着模板(函数模板或类模板)的所有定义仅在标题中。没有.cpp
文件。只有.h
文件(或其他一些扩展名,例如.hpp
或根本没有扩展名<vector>
,string>
等等)
C++ 编译器要求模板的定义存在于声明它们的同一文件中。因此,仅标头库既不是静态库也不是动态库。它的源代码库意味着您可以在标题中看到实现。您已经在代码中包含了头文件,这些头文件与库中的头文件一起编译。
请注意,C++ 标准库中使用模板的部分,如<vector>
、string>
、<map>
等是仅标头库。
实际上模板(类模板和函数模板)不能编译成静态或动态库链接到程序。正如术语本身所说,模板就是模板。这不是正常的代码;只有当您在代码中使用它传递模板参数(或者是type
or value
)时,编译器才会从函数/类模板中生成一个可编译的函数/类:
template<typename T>
struct A
{
T data;
};
struct B
{
int data;
};
在这里,A
不能编译成二进制(静态库或动态库),因为编译器不知道是什么T
。但是B
可以编译成二进制,因为编译器有完整的信息。
因此,您可以将短语“类模板 A”解读为:A
是类的模板。A
本身不是一个类。但B
它是一个类,它不是一个模板。
由于类模板A
不能编译为静态或动态库以链接到您的程序,因此A
只能作为header-only
具有完整源代码的库提供。同样地
一些库采用二进制文件的形式,您必须将其与项目链接,以及定义可用类或函数的头文件。“仅包含头文件的库”将是一个不包含二进制文件的库,只是包含在源代码中的头文件。
模板是为特定用途定制的类或函数;它们通常在头文件中定义,因为编译器必须读取它们的源代码才能自定义它们。在您确切知道将如何使用模板之前,您无法将模板编译为二进制文件,因此您将源代码与您自己的代码一起包含在内,然后编译器可以一起处理它们。
这恰好意味着该库仅作为标头重新分配。要使用它,您只需要在源文件中#include 它。
简短的回答是,模板很像编译器生成代码的宏。每次实例化它时(对于 esample,使用类似 的类型std::list<int>
),编译器必须拥有原始代码才能int
在模板类的代码中插入正确的类型(在本例中为 )。.h
这就是为什么每次您必须在文件中使用模板类时都将它们包含在文件中的原因.cpp
。
这意味着所有代码都在头文件中;没有与该库关联的库。这在实践中意味着什么——在最坏的情况下,这意味着作者甚至从未编译过代码:-)。最有可能的是,这意味着代码从未使用您使用的编译器、版本和选项的确切组合进行过测试,并且编译时间会大幅增加。另一方面,这意味着即使作者无法访问与您相同的编译器,您也可以使用该库,并且您不会被迫使用他在编译该库时使用的任何选项。或者,如果它是开源的,您不必自己构建库。
这意味着库中没有模块,只有标题。这意味着可以使用该库,而无需先对其进行编译和稍后链接;只需将标题包含在您自己的源模块中即可。
这种方法的好处是
- 它更容易包含,因为您不需要在构建系统中指定链接器选项。
- 您始终使用与其余代码相同的编译器(选项)编译所有库代码,因为库的函数已内联在您的代码中。
- 它可能会快很多。
在这种情况下,容器数据结构在其包含的数据类型上实现了模板化,因此无法完全编译。
对于模板库,可以仅在头文件(.h 文件)中提供所有功能,因为传统编译器需要模板类的完整定义才能实例化给定类型。除非库要提供预实例化的版本,或者模板库的某些部分不需要模板化,否则没有什么可以放入库中。
它是“仅标题”,因为它不包含单独的 .cpp 文件,仅包含 .h 文件,因此您可以将#include
所有库代码放入您的代码中。
这可能是有利的,因为您不必链接到可能非常痛苦的静态库。
这意味着您不必在开发的链接阶段链接任何外部库。您只需下载库并使用#include 宏即可使用该库。它简化了应用程序的部署,但有时会以更长的编译器时间为代价。