【问题标题】:What is the best explanation for the export keyword in the C++0x standard?C++0x 标准中 export 关键字的最佳解释是什么?
【发布时间】:2010-09-21 17:16:08
【问题描述】:

我知道在最初的 C++0x 标准中有一个名为 export 的特性。

但我找不到此功能的描述或解释。它应该做什么?另外:哪个编译器支持它?

【问题讨论】:

    标签: c++


    【解决方案1】:

    查看this的使用说明

    相当多的编译器不支持它,要么是因为它太新,要么是在 gcc 的情况下——因为它们不赞成。

    这篇文章描述了对许多编译器的标准支持。 Visual Studio support for new C / C++ standards?

    【讨论】:

    • 它不是太新,它和 C++ 98 标准中的其他特性一样已有 10 年的历史了! :D 更多的是实现它需要重新设计编译器,而且他们认为这不值得。
    • 它使链接器变得棘手,特别是如果您想在链接阶段进行大量巧妙的整个程序优化
    【解决方案2】:

    尽管标准 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&lt;int&gt;。在蛮力的努力中,可以通过在其末尾添加以下行将其添加到 xyz.cpp:

    template xyz<int>;
    

    请求实例化(全部)xyz&lt;int&gt;。不过这有点不对,因为这意味着每次产生新的 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.htmlhttp://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。使用前面显示的命令行,编译器可能会自动为您完成所有操作。

    【讨论】:

    • 注意 Greg Rogers' answer 和那里的 cmets - export 关键字已从标准中删除,可能永远不会在另一个编译器中实现。
    【解决方案3】:

    导出是一种在链接器和编译器之间引入循环依赖的功能。正如其他人所指出的,它允许一个翻译单元包含在另一个翻译单元中使用的模板的定义。链接器将首先检测到这一点,但它需要编译器来实例化模板。这涉及真正的艰苦工作,例如名称查找。

    Comeau 大约在 5 年前 IIRC 首次介绍了它。它在我获得的第一个 beta 版本中运行良好。如果模板 A 和 B 来自不同的 TU,即使像 A 使用 B 使用 A 使用 B 使用 A 之类的测试用例也可以工作。当然,链接器反复调用编译器,但所有名称查找工作正常。实例化 A 从 A.cpp 中找到在 B.cpp 中不可见的名称。

    【讨论】:

      【解决方案4】:

      请参阅 herehere 了解 Herb Sutter 对该主题的处理。

      基本上:export 仅在 one 编译器中实现 - 在该实现中,export 实际上增加了模板定义和声明之间的耦合,而引入 export 的唯一目的是减少这种耦合。

      这就是为什么大多数编译器不打扰的原因。我原以为他们会从 C++0x 语言中删除导出,但我认为他们没有。也许有一天会有一种好方法来实现具有预期用途的导出。

      【讨论】:

      • Herb Sutter 是 Microsoft 员工。他试图从 C++0x 中删除导出,但失败了。所以他的观点可能有些偏颇。披露:我否决了他对 ISO 的提议。
      • 想评论一下为什么?我能够对此进行挖掘的所有内容都表明该功能是一个死问题,无论它是否保留在标准中。
      • Sutter 作为 MS 员工与此无关,他只是认为 export 没有成功,所以认为应该删除它。
      • @KTC:确定吗?在我的最终草案 2.12 [lex.key]/1 中,它说:“表 3 中显示的标识符保留用作关键字(即,它们在第 7 阶段无条件地被视为关键字),除非在属性中 - token (7.6.1) [注意:export 关键字未使用,但保留供将来使用。- 结束注]”这似乎是说在当前草案中 export 功能已消失。另请注意,唯一支持 export 的编译器实现者推动从新标准中删除该功能。
      • @David Rodríguez,嗯,是的,当我写那条评论时,它应该是“功能完整”的。然后他们开始再次取消功能,包括重新讨论和随后删除导出。我不会说 EDG 推动了它的移除,而是他们同意它。 Herb 在链接文章中关于 EDG 的评论实际上非常有趣。
      【解决方案5】:

      简单地说:

      export 允许您在编写模板类时将声明(即标头)与定义(即代码)分开。如果你的编译器不支持export,那么你需要将声明和定义放在一个地方。

      【讨论】:

        【解决方案6】:

        目前(据我所知)唯一支持导出模板的编译器是 Comeau,它是 Borland C++ Builder X 附带的,但不是当前的 C++ Builder 和英特尔(至少是非官方的,如果不是官方的,不确定)。

        【讨论】:

          【解决方案7】:
          猜你喜欢
          • 2010-10-11
          • 1970-01-01
          • 2011-04-26
          • 2010-09-13
          • 1970-01-01
          • 2011-04-13
          相关资源
          最近更新 更多