【发布时间】:2010-09-21 17:16:08
【问题描述】:
我知道在最初的 C++0x 标准中有一个名为 export 的特性。
但我找不到此功能的描述或解释。它应该做什么?另外:哪个编译器支持它?
【问题讨论】:
标签: c++
我知道在最初的 C++0x 标准中有一个名为 export 的特性。
但我找不到此功能的描述或解释。它应该做什么?另外:哪个编译器支持它?
【问题讨论】:
标签: c++
查看this的使用说明
相当多的编译器不支持它,要么是因为它太新,要么是在 gcc 的情况下——因为它们不赞成。
这篇文章描述了对许多编译器的标准支持。 Visual Studio support for new C / C++ standards?
【讨论】:
尽管标准 C++ 没有这样的要求,但一些编译器要求所有函数模板都需要在使用它的每个翻译单元中可用。实际上,对于那些编译器,模板函数的主体必须在一个头文件。重复一遍:这意味着那些编译器不允许在非头文件(如 .cpp 文件)中定义它们。澄清一下,在 C++ese 中,这意味着:
// ORIGINAL version of xyz.h
template <typename T>
struct xyz
{
xyz();
~xyz();
};
不会对 ctor 和 dtors 的这些定义感到满意:
// ORIGINAL version of xyz.cpp
#include "xyz.h"
template <typename T>
xyz<T>::xyz() {}
template <typename T>
xyz<T>::~xyz() {}
因为使用它:
// main.cpp
#include "xyz.h"
int main()
{
xyz<int> xyzint;
return 0;
}
会产生错误。例如,使用 Comeau C++,你会得到:
C:\export>como xyz.cpp main.cpp C++'ing xyz.cpp... Comeau C/C++ 4.3.4.1 (May 29 2004 23:08:11) for MS_WINDOWS_x86 Copyright 1988-2004 Comeau Computing. All rights reserved. MODE:non-strict warnings microsoft C++ C++'ing main.cpp... Comeau C/C++ 4.3.4.1 (May 29 2004 23:08:11) for MS_WINDOWS_x86 Copyright 1988-2004 Comeau Computing. All rights reserved. MODE:non-strict warnings microsoft C++ main.obj : error LNK2001: unresolved external symbol xyz<T1>::~xyz<int>() [with T1=int] main.obj : error LNK2019: unresolved external symbol xyz<T1>::xyz<int>() [with T1=int] referenced in function _main aout.exe : fatal error LNK1120: 2 unresolved externals
因为在 xyz.cpp 中没有使用 ctor 或 dtor,因此不需要从那里进行实例化。无论好坏,这就是模板的工作原理。
解决此问题的一种方法是显式请求 xyz 的实例化,在此示例中为 xyz<int>。在蛮力的努力中,可以通过在其末尾添加以下行将其添加到 xyz.cpp:
template xyz<int>;
请求实例化(全部)xyz<int>。不过这有点不对,因为这意味着每次产生新的 xyz 类型时,都必须修改实现文件 xyz.cpp。避免该文件的一种侵入性较小的方法是创建另一个:
// xyztir.cpp
#include "xyz.cpp" // .cpp file!!!, not .h file!!
template xyz<int>;
这仍然有些痛苦,因为每次产生新的 xyz 时仍然需要手动干预。在一个重要的程序中,这可能是一个不合理的维护需求。
因此,解决此问题的另一种方法是将#include "xyz.cpp" 放入 xyz.h 的末尾:
// xyz.h
// ... previous content of xyz.h ...
#include "xyz.cpp"
您当然可以将 xyz.cpp 的内容直接带到(剪切和粘贴)到 xyz.h 的末尾,从而摆脱 xyz.cpp;这是文件组织的问题,最终预处理的结果将是相同的,因为 ctor 和 dtor 主体将位于标头中,因此会被带入任何编译请求,因为那将使用各自的标头。无论哪种方式,这都会产生副作用,即现在每个模板都在您的头文件中。它可能会减慢编译速度,并可能导致代码膨胀。处理后者的一种方法是将有问题的函数(在本例中为 ctor 和 dtor)声明为内联函数,因此这需要您在运行示例中修改 xyz.cpp。
顺便说一句,一些编译器还要求在类内内联定义某些函数,而不是在类外定义,因此对于这些编译器,上述设置需要进一步调整。请注意,这是编译器问题,而不是标准 C++ 问题之一,因此并非所有编译器都需要此问题。例如,Comeau C++ 没有,也不应该。查看http://www.comeaucomputing.com/4.0/docs/userman/ati.html 了解我们当前设置的详细信息。简而言之,Comeau C++ 支持许多模型,包括一个接近于 export 关键字意图的模型(作为扩展),甚至支持 export 本身。
最后,请注意 C++ export 关键字旨在缓解原始问题。然而,目前 Comeau C++ 是唯一被公开支持导出的编译器。有关详细信息,请参阅 http://www.comeaucomputing.com/4.0/docs/userman/export.html 和 http://www.comeaucomputing.com/4.3.0/minor/win95+/43stuff.txt。希望随着其他编译器符合标准 C++,这种情况将会改变。在上面的示例中,使用导出意味着返回产生链接器错误的原始代码,并进行更改:在 xyz.h 中使用 export 关键字声明模板:
// xyz.h
export
// ... ORIGINAL contents of xyz.h ...
xyz.cpp 中的 ctor 和 dtor 将通过#includeing xyz.h 简单地导出,它已经这样做了。因此,在这种情况下,您不需要 xyztir.cpp,也不需要 xyz.cpp 末尾的实例化请求,也不需要手动将 ctor 或 dtor 带入 xyz.h。使用前面显示的命令行,编译器可能会自动为您完成所有操作。
【讨论】:
export 关键字已从标准中删除,可能永远不会在另一个编译器中实现。
导出是一种在链接器和编译器之间引入循环依赖的功能。正如其他人所指出的,它允许一个翻译单元包含在另一个翻译单元中使用的模板的定义。链接器将首先检测到这一点,但它需要编译器来实例化模板。这涉及真正的艰苦工作,例如名称查找。
Comeau 大约在 5 年前 IIRC 首次介绍了它。它在我获得的第一个 beta 版本中运行良好。如果模板 A 和 B 来自不同的 TU,即使像 A 使用 B 使用 A 使用 B 使用 A 之类的测试用例也可以工作。当然,链接器反复调用编译器,但所有名称查找工作正常。实例化 A 从 A.cpp 中找到在 B.cpp 中不可见的名称。
【讨论】:
【讨论】:
export 功能已消失。另请注意,唯一支持 export 的编译器实现者推动从新标准中删除该功能。
简单地说:
export 允许您在编写模板类时将声明(即标头)与定义(即代码)分开。如果你的编译器不支持export,那么你需要将声明和定义放在一个地方。
【讨论】:
目前(据我所知)唯一支持导出模板的编译器是 Comeau,它是 Borland C++ Builder X 附带的,但不是当前的 C++ Builder 和英特尔(至少是非官方的,如果不是官方的,不确定)。
【讨论】: