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

How should I write my C++ to be prepared for C++ modules?

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

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

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

Is it possible to use modules and still maintain compatibility with older compilers that do not support it?

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

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

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

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

When starting a new project now, what should I pay attention to in order to be able to adopt the modules feature when it is eventually released in my compiler?

视情况而定。如果您的项目是企业项目并且让您吃到盘子里的食物,我会等待几年,一旦它在马厩中发布,以便它得到广泛的适应。另一方面,如果您的项目能够负担得起前沿技术,请务必使用模块。

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

There are already two compilers that support C++ modules

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

Microsoft 方法似乎是最受关注的方法,主要是因为 Microsoft 在其实施中投入的资源比目前任何 clang 人都多。请参阅 https://llvm.org/bugs/buglist.cgi?list_id=100798&query_format=advanced&component=Modules&product=clang 了解我的意思,C++ 模块中存在一些严重的问题,而 C 模块或特别是 Objective C 在现实世界代码中看起来更有用。 Visual Studio 最大和最重要的客户 Microsoft 正在大力推动 Modules,因为它解决了大量的内部构建可扩展性问题,并且 Microsoft 的内部代码是现有任何地方最难编译的 C++,因此您可以' 抛出除 MSVC 之外的任何编译器(例如,祝你好运,让 clang 或 GCC 编译 40k 行函数)。因此,Google 等使用的 clang 构建技巧不适用于 Microsoft,他们迫切需要尽早修复它。

这并不是说在实践中将 Microsoft 提案应用于大型现实世界代码库时没有一些严重的设计缺陷。但是 Gaby 认为您应该重构模块的代码,虽然我不同意,但我可以理解他的观点。

When starting a new project now, what should I pay attention to in order to be able to adopt the modules feature when it is eventually released in my compiler?

就 Microsoft 的编译器目前期望实现模块而言,您应该确保您的库可用于所有这些形式:

  1. 动态库
  2. 静态库
  3. Header 只有图书馆

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

稍后的 Visual Studio 将允许将模块定义文件(.ifc 文件)作为资源链接到 DLL 中。这将最终消除 MSVC 上对 .lib 和 .dll 区别的需要,您只需向编译器提供一个 DLL,并且在模块导入时全部 "just works",不需要 headers 或任何其他需要的东西。这当然有点像 COM,但没有 COM 的大部分优点。

Is it possible to use modules in a single codebase and still maintain compatibility with older compilers that do not support it?

我假设您指的是上面插入的粗体文本。

答案通常是肯定的,而且预处理器宏更有趣。 #include <someheader> 可以在 header 中变成 import someheader 因为预处理器仍然照常工作。因此,您可以使用 C++ 模块支持标记单个库 headers,如下所示:

// 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-ready 的对您的源代码的最小可能更改集。你会注意到我对构建系统只字未提,这是因为我仍在调试我编写的 cmake 工具,以便将所有这些东西无缝地获取到 "just work",我希望调试它几个月。期待在明年或后年的 C++ 会议上看到它:)