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

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

本文关键字:C++ 模块 何编写 我的 我应该      更新时间:2023-10-16

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

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

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

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

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

叮当声:http://clang.llvm.org/docs/Modules.htmlMS与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=高级&component=模块&product=clang就我的意思而言,C++的模块中有一些大的缺陷,而C的模块,尤其是Objective C的模块在现实世界的代码中看起来更有用。Visual Studio最大、最重要的客户微软正在大力推动模块,因为它解决了大量内部构建可扩展性问题,而微软的内部代码是目前最难编译的C++之一,因此除了MSVC之外,你不能再使用任何编译器(例如,祝你好运,让clang或GCC编译40k行函数)。因此,谷歌等公司使用的叮当声构建技巧对微软来说是不可用的,他们迫切需要尽快修复它。

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

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

就微软的编译器目前有望实现模块而言,你应该确保你的库在所有这些形式中都可用:

  1. 动态库
  2. 静态库
  3. 仅标题库

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

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

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

我想你是指上面插入的粗体文字。

答案通常是肯定的,甚至还有更多的预处理器宏乐趣。由于预处理器仍然照常工作,CCD_ 1可以在报头内变成CCD_。因此,您可以标记带有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"

如果编译器有/experial:modules/DMODULES_ENABLED,那么您的应用程序会自动使用库的C++模块版本。如果没有,您可以像我们一直做的那样获得内联包含。

我认为这些是对源代码的最小可能的更改集,以使您的代码模块现在做好准备。你会注意到,我对构建系统只字未提,这是因为我仍在调试我编写的cmake工具,以使所有这些东西无缝地"工作",我预计还会调试几个月。预计可能会在明年或次年的C++会议上看到它:)

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

不,这是不可能的。可能会使用一些#ifdef魔法,比如

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

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

如果你真的想遵循这种方法,检测我刚刚编写的"CXX17_MODULES"的最简单方法是编译一个小测试程序,该程序使用你选择的构建系统中的模块,并为每个人定义一个全局,以判断编译是否成功。

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

这取决于情况。如果你的项目是企业级的,能让你有饭吃,我会等几年,等它在马厩里发布,这样它就会被广泛改编。另一方面,如果你的项目能承受得起流血的风险,那么无论如何,使用模块。

基本上,Python3和Python2的情况是一样的,或者与PHP7和PHP5不太相关。你需要在成为一名优秀的最新程序员和不惹恼Debian上的人之间找到平衡;-)