如何避免 header only 库中的循环依赖?
How can I avoid circular dependencies in a header only library?
我正在开发一个仅 C++ header 的库。
代码中有几个部分遵循这种模式:
holder.h
#pragma once
#include "sub.h"
struct Holder
{
void f();
Sub s;
};
sub.h
#pragma once
struct Holder;
struct Sub
{
void g(Holder& h);
};
#include "sub.ipp"
sub.ipp
#include "holder.h"
inline void Sub::g(Holder& h)
{
h.f();
}
sub.h 使用前向声明避免了对 Holder 的循环依赖。然而,在 holder.h 作为 Holder class 包含一个 Sub 成员它需要在 sub.h 中查看 Sub 的完整声明。然而,sub.h 引入了 sub.ipp 中的实现,它还不能实例化,因为它需要定义Holder 并且我们已经在 holder.h 中,所以我们不能再包含它了。
作为这些 header 中任何一个的用户,我只想包含正确的 .h 文件,而不必担心手动包含在奇怪的地方纠正 .ipp 个文件。
这个问题的标准解决方案是什么?
struct Sub
{
void g(Holder& h);
};
void Sub::g(Holder& h)
{
h.f();
}
Non-inline 函数在 header-only 库中无法正常工作,因为 header 通常包含在多个翻译单元中。您应该改用内联函数。
How can I avoid circular dependencies in a header only library?
您必须将函数的定义与 class 的定义分开。我的意思是,它们已经在单独的文件中,但是定义 class 的 header 不能包含函数定义。这允许打破依赖循环。
这可能是个人喜好问题,但我也不喜欢不能独立运行的“ipp”header。
示例:
detail/holder_class_only.h
#pragma once
#include "detail/sub_class_only.h"
struct Holder
{
inline void f(); // note inline
Sub s;
};
detail/sub_class_only.h
#pragma once
struct Holder;
struct Sub
{
inline void g(Holder& h); // note inline
};
detail/holder_functions.h
#pragma once
#include "detail/holder_class_only.h"
void Holder::f()
{
}
#include "detail/sub_functions.h"
detail/sub_functions.h
#pragma once
#include "detail/sub_class_only.h"
#include "holder.h"
void Sub::g(Holder& h)
{
h.f();
}
sub.h
#pragma once
#include "detail/sub_class_only.h"
#include "detail/sub_functions.h"
holder.h
#pragma once
#include "detail/holder_class_only.h"
#include "detail/holder_functions.h"
注意:未经测试,可能包含错误。
我正在开发一个仅 C++ header 的库。
代码中有几个部分遵循这种模式:
holder.h
#pragma once
#include "sub.h"
struct Holder
{
void f();
Sub s;
};
sub.h
#pragma once
struct Holder;
struct Sub
{
void g(Holder& h);
};
#include "sub.ipp"
sub.ipp
#include "holder.h"
inline void Sub::g(Holder& h)
{
h.f();
}
sub.h 使用前向声明避免了对 Holder 的循环依赖。然而,在 holder.h 作为 Holder class 包含一个 Sub 成员它需要在 sub.h 中查看 Sub 的完整声明。然而,sub.h 引入了 sub.ipp 中的实现,它还不能实例化,因为它需要定义Holder 并且我们已经在 holder.h 中,所以我们不能再包含它了。
作为这些 header 中任何一个的用户,我只想包含正确的 .h 文件,而不必担心手动包含在奇怪的地方纠正 .ipp 个文件。
这个问题的标准解决方案是什么?
struct Sub { void g(Holder& h); }; void Sub::g(Holder& h) { h.f(); }
Non-inline 函数在 header-only 库中无法正常工作,因为 header 通常包含在多个翻译单元中。您应该改用内联函数。
How can I avoid circular dependencies in a header only library?
您必须将函数的定义与 class 的定义分开。我的意思是,它们已经在单独的文件中,但是定义 class 的 header 不能包含函数定义。这允许打破依赖循环。
这可能是个人喜好问题,但我也不喜欢不能独立运行的“ipp”header。
示例:
detail/holder_class_only.h
#pragma once
#include "detail/sub_class_only.h"
struct Holder
{
inline void f(); // note inline
Sub s;
};
detail/sub_class_only.h
#pragma once
struct Holder;
struct Sub
{
inline void g(Holder& h); // note inline
};
detail/holder_functions.h
#pragma once
#include "detail/holder_class_only.h"
void Holder::f()
{
}
#include "detail/sub_functions.h"
detail/sub_functions.h
#pragma once
#include "detail/sub_class_only.h"
#include "holder.h"
void Sub::g(Holder& h)
{
h.f();
}
sub.h
#pragma once
#include "detail/sub_class_only.h"
#include "detail/sub_functions.h"
holder.h
#pragma once
#include "detail/holder_class_only.h"
#include "detail/holder_functions.h"
注意:未经测试,可能包含错误。