修复基于模块的库中的自阻塞包含

Fixing self-blocking includes in a module based library

本文关键字:包含 于模块 模块      更新时间:2023-10-16

我已经编写了一个简单的模板化、基于模块的头库。对于基于模块的,我的意思是只能包括string.hdynarray.h,并且标头将引入其所有依赖项。

现在,由于这个系统的工作方式,我面临着缺少类型的问题。一个模块可以:

  • #include所有依赖项
  • 定义接口class Foo
  • #include实现文件

不幸的是,在某些情况下,在包含任何实现之前,需要有两个接口可用。我在这里分解了问题:

string.h

#pragma once
// A string depends on a DynArray.
#include "dynarray.h"
template<typename E>
class String {
public:
DynArray<E> arr;
/* ... */
};
// Include the implementation of all the different functions (irrelevant here)
#include "string_impl.h"

dynary.h

#pragma once
// The dynarray header has no direct dependencies
template<typename E>
class DynArray {
public:
/* ... */
E& Get(int index);
};
// Include the implementation of all the different functions
#include "dynarray_impl.h"

dynary_impl.h

#pragma once
// The dynarray implementation needs the OutOfRangeException class
#include "out_of_range_exception.h"
template<typename E>
E& DynArray<E>::Get(int index) {
if (index >= size) {
throw OutOfRangeException("Some error message");
}
}

out_of_range_exception.h

class OutOfRangeException {
public:
String message;
OutOfRangeException(String message) {
/* ... */
}
};

由于在其底部包含模块的实现,当在某个地方包含string.h时,dynarray_impl.h及其out_of_range_exception.h的内容位于字符串类接口之前。所以CCD_ 10中没有定义CCD_ 9。

显然,解决方案是在定义字符串接口之后只延迟dyarray(dynarr_impl.h)的实现部分。问题是,如果不创建某种通用头文件,我不知道如何做到这一点,因为它与基于模块的方法不兼容。

您的问题是接口和实现都有一个文件。

#include使用该文件表示依赖于X的接口和X的实现。

有时你只想依赖X.的接口

X接口:

  • #include接口的所有依赖项
  • 定义一个接口class X

X实现:

  • #include接口
  • #include实现的所有依赖项
  • 定义class X的实现

从某种意义上说,这是两个独立的模块,其中一个依赖于另一个。这允许客户端只依赖于另一种类型的接口,或者只依赖于它的实现,或者先依赖于接口,然后再依赖于实现。

通常您只能使用#include "X.h",除非您有实现的循环依赖关系。然后在某个地方你必须用#include "X_interface.h"打破链条


如果您真的想使用单个头文件,您可以取消#pragma once,并拥有可以包含在"两种模式"中的头文件。这会大大降低构建时间,因为任何这样的机制都需要编译器打开文件来检查是否有代码;大多数编译器可以检测到#ifdef头保护和#pragma once,并避免重新打开它知道不包含任何感兴趣的文件。但这种技术无法处理"可以在不同模式下多次包含"的头文件。