我应该如何编写C ++来为C ++模块做好准备?

时间:2016-01-07 09:51:58

标签: c++ backwards-compatibility future-proof c++20 c++-modules

已经有两个支持C ++模块的编译器:

现在开始一个新项目时,为了能够在我的编译器最终发布时采用模块功能,我应该注意什么?

是否可以使用模块并仍然保持与不支持它的旧编译器的兼容性?

2 个答案:

答案 0 :(得分:26)

  

已经有两个支持C ++模块的编译器

     

clang:http://clang.llvm.org/docs/Modules.html   MS VS 2015:http://blogs.msdn.com/b/vcblog/archive/2015/12/03/c-modules-in-vs-2015-update-1.aspx

微软的方法似乎是获得最大牵引力的方法,主要是因为微软在实施方面投入的资源远远超过目前任何一个铿锵的民众。请参阅https://llvm.org/bugs/buglist.cgi?list_id=100798&query_format=advanced&component=Modules&product=clang我的意思,在C ++模块中有一些大的showstopper错误,而C或特别是Objective C的模块在现实代码中看起来更有用。 Visual Studio的最大和最重要的客户,微软,正在努力推动模块,因为它解决了大量的内部构建可扩展性问题,而微软的内部代码是现有任何地方编译的最难的C ++之一所以你不能抛出除MSVC以外的任何编译器(例如,好运得到clang或GCC来编译40k行函数)。因此,谷歌等使用的clang构建技巧对微软来说是不可用的,并且他们迫切需要尽快修复它。

在实践中应用于大型真实世界的代码库时,并不是说微软的提案没有一些严重的设计缺陷。然而,Gaby认为你应该重构你的模块代码,虽然我不同意,但我可以看到他来自哪里。

  

现在开始一个新项目时,为了能够在我的编译器最终发布时采用模块功能,我应该注意什么?

目前预计Microsoft的编译器将实现模块,您应该确保您的库可以以所有这些形式使用:

  1. 动态库
  2. 静态库
  3. 仅限标题库
  4. 许多人都非常惊讶的是,目前预计会实现的C ++模块保留了这些区别,所以现在你得到了所有三个的C ++模块变体,看起来最先看就像人们对C ++模块的期望一样,最后看起来最像是一个更有用的预编译头。您应该支持这些变体的原因是因为您可以重用大多数相同的预处理器机制来支持C ++模块而只需要很少的额外工作。

    稍后的Visual Studio将允许将模块定义文件(.ifc文件)作为资源链接到DLL中。这将最终消除对MSVC上的.lib和.dll区别的需要,你只需要为编译器提供一个DLL,而且它只是工作"在模块导入,没有标题或任何其他需要。这当然闻起来有点像COM,但没有COM的大部分好处。

      

    是否可以在单个代码库中使用模块,并且仍然保持与不支持它的旧编译器的兼容性?

    我假设您的意思是上面插入的粗体文字。

    答案通常是肯定的,甚至更多的预处理器宏乐趣。 #include <someheader>可以在标题中变成import someheader,因为预处理器仍然像往常一样工作。因此,您可以使用C ++模块支持标记单个库头,如下所示:

    // someheader.hpp
    
    #if MODULES_ENABLED
    #  ifndef EXPORTING_MODULE
    import someheader;  // Bring in the precompiled module from the database
    // Do NOT set NEED_DEFINE so this include exits out doing nothing more
    #  else
    // We are at the generating the module stage, so mark up the namespace for export
    #    define SOMEHEADER_DECL export
    #    define NEED_DEFINE
    #  endif
    #else
    // Modules are not turned on, so declare everything inline as per the old way
    #  define SOMEHEADER_DECL
    #  define NEED_DEFINE
    #endif
    
    #ifdef NEED_DEFINE
    SOMEHEADER_DECL namespace someheader
    {
      // usual classes and decls here
    }
    #endif
    

    现在在你的main.cpp或其他任何内容中,你只需:

    #include "someheader.hpp"
    

    ...如果编译器有/ experimental:modules / DMODULES_ENABLED,那么您的应用程序会自动使用库的C ++ Modules版本。如果它没有,你就会得到内联,因为我们总是这样做。

    我认为这些是您的源代码的最小可能更改集,以使您的代码模块现在就绪。你会注意到我对构建系统一无所知,这是因为我还在调试我编写的cmake工具,以便将所有这些东西都用到&#34;只是工作&#34;无缝地,我希望它可以调试几个月。期待在明年或之后的一年的C ++大会上看到它:)

答案 1 :(得分:3)

  

是否可以使用模块并仍然保持与不支持它的旧编译器的兼容性?

不,这是不可能的。有可能使用这样的#ifdef魔法:

#ifdef CXX17_MODULES
    ...
#else
    #pragma once, #include "..." etc.
#endif

但这意味着您仍然需要提供.h支持,从而失去所有好处,而且您的代码库现在看起来非常难看。

如果您确实想要采用这种方法,最简单的方法是检测&#34; CXX17_MODULES&#34;我刚刚编写的是编译一个小型测试程序,该程序使用具有您选择的构建系统的模块,并为每个人定义一个全局,以便了解编译是否成功。

  

现在开始一个新项目时,为了能够在我的编译器最终发布时采用模块功能,我应该注意什么?

这取决于。如果您的项目是企业并且让您获得食物,我会在马厩中释放后等待几年,以便广泛适应。另一方面,如果您的项目能够成为最前沿的,请务必使用模块。

基本上,它与Python3和Python2的故事相同,或者与PHP7和PHP5相关性较低。你需要在成为一名优秀的最新程序员之间找到平衡,而不是在Debian上烦人; - )