为什么 C++模板定义需要在标题中吗?
可能的重复:
为什么应该模板类的实现和声明在同一个头文件中吗?
例如,定义模板类时,为什么类方法的实现需要位于头文件中?为什么它们不能位于实现文件(cpp/cxx)中?
Possible Duplicate:
Why should the implementation and the declaration of a template class be in the same header file?
e.g when defining a template class why do the implementations of the class methods need to be in the header? Why can't they be in a implementation file (cpp/cxx)?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
模板类不是一个类,它是一个可用于创建类的模板。当您实例化这样的类时,例如
MyTemplate
,编译器会当场创建该类。为了创建它,它必须查看所有模板化成员函数(以便它可以使用模板创建实际成员函数,例如MyTemplate::foo()
),因此这些模板化成员函数必须位于标头中。如果成员不在标头中,编译器将简单地假设它们存在于其他位置,并从模板化函数声明创建实际的函数声明,这会给您带来链接器错误。
“export”关键字应该可以解决这个问题,但很少有编译器支持它(我只知道 Comeau)。
您还可以显式实例化
MyTemplate
- 然后编译器在编译包含MyTemplate< 的 cpp 文件时将为
MyTemplate
创建实际的成员函数。 /code> 成员函数定义模板。A template class is not a class, it's a template that can be used to create a class. When you instantiate such a class, e.g.
MyTemplate<int>
, the compiler creates the class on the spot. In order to create it, it has to see all the templated member functions (so that it can use the templates to create actual member functions such asMyTemplate<int>::foo()
), and therefore these templated member functions must be in the header.If the members are not in the header, the compiler will simply assume that they exist somewhere else and just create actual function declarations from the templated function declarations, and this gives you linker errors.
The "export" keyword is supposed to fix this, but few compilers support it (I only know of Comeau).
You can also explicitly instantiate
MyTemplate<int>
- then the compiler will create actual member functions forMyTemplate<int>
when it compiles the cpp files containing theMyTemplate
member function definition templates.它们在实例化时需要对编译器可见。这基本上意味着,如果您在标头中发布模板,并且您依赖于隐式实例化,那么包含该标头的所有翻译单元都必须可以看到定义。
如果您要显式实例化模板,则不需要在标头中定义它们,但这在大多数情况下不是一个好主意。
至于原因,基本上可以归结为这样一个事实:模板不是在编译器解析定义时编译的,而是在实例化模板时编译的,然后针对特定的实例化类型进行编译。
They need to be visible for the compiler when they are instantiated. That basically means that if you are publishing the template in a header, the definitions have to be visible by all translation units that include that header if you depend on implicit instantiation.
They need not be defined in the header if you are going to explicitly instantiate the templates, but this is in most cases not a good idea.
As to the reason, it basically boils down to the fact that templates are not compiled when the compiler parses the definition, but rather when they are instantiated, and then they are compiled for the particular instantiation type.
如果您的编译器支持
导出
,那么它就不支持。只有基于 EDG 的编译器支持导出
,因此它将从 C++0x 中删除。非导出模板要求编译器可以看到完整的模板定义,以便为您作为参数提供的特定类型实例化它。例如:
现在,当您在某个翻译单元中编写
X(5)
时,编译器作为编译该翻译单元的一部分必须检查 X 的构造函数类型正确,为其生成代码,等等。因此它必须看到 X 的定义,以便它可以允许X(5)
但禁止X(5)
。确保编译器在使用它的所有翻译单元中看到相同模板定义的唯一明智方法是将定义放入头文件中。不过,就标准而言,欢迎您手动复制并粘贴它,或者在仅在该翻译单元中使用的 cpp 文件中定义模板。
export
实际上告诉编译器必须将模板定义的解析形式输出到一种特殊类型的目标文件中。然后链接器执行模板实例化。使用普通的工具链,编译器足够智能来执行模板实例化,而链接器则不然。请记住,模板实例化必须完成编译器除了基本解析之外所做的几乎所有事情。If your compiler supports
export
, then it doesn't. Only EDG-based compilers supportexport
, and it's going to be removed from C++0x because of that.Non-exported templates require that the compiler can see the full template definition, in order to instantiate it for the particular types you supply as arguments. For example:
Now, when you write
X<float>(5)
in some translation unit, the compiler as part of compiling that translation unit must check that the constructor of X is type-correct, generate the code for it, and so on. Hence it must see the definition of X, so that it can permitX<float>(5)
but forbidX<char*>(5)
.The only sensible way to ensure that the compiler sees the same template definition in all translation units that use it, is to put the definition in a header file. As far as the standard is concerned, though, you're welcome to copy-and-paste it manually, or to define a template in a cpp file that is used only in that one translation unit.
export
in effect tells the compiler that it must output a parsed form of the template definition into a special kind of object file. Then the linker performs template instantiation. With normal toolchains, the compiler is smart enough to perform template instantiation and the linker isn't. Bear in mind that template instantiation has to do pretty much everything that the compiler does beyond basic parsing.它们可以位于 CPP 文件中。
问题源于这样的事实:编译器在每个翻译单元的基础上构建模板类的特定实例化的代码(例如std::vector)。在 CPP 文件中定义函数的问题是,您需要在该 CPP 文件中定义每种可能的形式(这称为模板专业化)。
因此,对于上面示例的 int 向量,您可以使用专门化在 CPP 文件中为 int 情况定义一个函数。
例如,
当然这样做可以产生针对特定情况进行优化的优势,但它确实让您了解 STL 会引入多少代码膨胀!至少所有函数都没有像某些编译器过去那样定义为内联;)
They can be in a CPP file.
The problem arises from the fact that the compiler builds the code for a specific instantiation of a template class (eg std::vector< int >) on a per translation unit basis. The problem with defining the functions in a CPP file is that you will need to define every possible form in that CPP file (this is called template specialization).
So for that int vector exampled above you could define a function in a CPP file for the int case using specialization.
e.g
Of course doing this can produce the advantage of optimisation for specific cases but it does give you an idea of just how much code bloat can be introduced by STL! At least all the functions aren't defined as inline as a certain compiler used to do ;)
模板的这一方面称为编译模型,不要与 C++如何链接模板实例.
实例化机制是回答“实例化何时生成?”的问题,实例化模型是回答“来源在哪里?”的问题。
有两种标准编译模型:
包含,您知道的一种,其中定义必须可用,
分离,其中允许借助关键字
export
将定义放在其他地方。该标准已从标准中删除,并且在 C++0X 中不可用。删除的原因之一是它没有被广泛实现(只有一种实现)。请参阅 C++ 模板、David Vandevoorde 和 Nicolai Josuttis 编写的完整指南或 http://www.有关更多信息,请访问 bourguet.org/v2/cpplang/export.pdf,分离编译模型是后面那篇论文的主题。
That aspect of template is called the compilation model, not to be confused with the instantiation mechanism which was the subject of How does C++ link template instances.
The instantiation mechanism is the answer to the question "When is the instantiation generated?", the instantiation model is the answer to "Where the source are found?"
There are two standards compilation model:
inclusion, the one that you know, where the definition must be available,
separated, which allows to put the definition somewhere else with the help of the keyword
export
. That one has been removed from the standard and won't be available in C++0X. One of the raison for removal was that it wasn't widely implemented (only one implementation).See C++ Templates, The Complete Guide by David Vandevoorde and Nicolai Josuttis or http://www.bourguet.org/v2/cpplang/export.pdf for more information, the separated compilation model being the subject of that later paper.