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

use*_*610 54 c++ backwards-compatibility future-proof c++20 c++-modules

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

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

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

Nia*_*las 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-更新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线路功能).因此,Google等使用的clang构建技巧并不适用于Microsoft,并且他们迫切需要尽快修复它.

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

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

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

  1. 动态库
  2. 静态库
  3. 仅限标头库

对于许多人来说非常令人惊讶的是,目前预期要实现的C++模块保留了这些区别,所以现在你得到了上述所有三个的C++模块变体,第一个看起来像人们期望的C++模块,而最后一个看起来最像是一个更有用的预编译头.您应该支持这些变体的原因是因为您可以重用大多数相同的预处理器机制来支持C++模块而只需要很少的额外工作.

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

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

我假设你的意思是上面插入的粗体文字.

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

// 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
Run Code Online (Sandbox Code Playgroud)

现在在你的main.cpp或其他什么,你只需:

#include "someheader.hpp"
Run Code Online (Sandbox Code Playgroud)

...如果编译器有/ experimental:modules/DMODULES_ENABLED,那么您的应用程序会自动使用库的C++ Modules版本.如果没有,你就会像我们一直那样得到内联.

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


rr-*_*rr- 5

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

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

#ifdef CXX17_MODULES
    ...
#else
    #pragma once, #include "..." etc.
#endif
Run Code Online (Sandbox Code Playgroud)

但这意味着您仍然需要提供.h支持并因此失去所有好处,而且您的代码库现在看起来很丑陋。

如果您确实想遵循这种方法,检测CXX17_MODULES我刚刚编写的“ ”的最简单方法是编译一个小测试程序,该程序使用带有您选择的构建系统的模块,并定义一个全局变量供大家查看是否编译成功与否。

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

这取决于。如果您的项目是企业项目并且让您吃得饱饱的,我会等几年,等它在马厩中发布,以便它被广泛采用。另一方面,如果您的项目能够承受前沿技术,请务必使用模块。

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