提问人:Eyal Kamitchi 提问时间:7/19/2023 更新时间:7/19/2023 访问量:70
如何使用“using”指令拆分循环依赖关系
how to split cyclic dependency with 'using' directive
问:
假设类 A 和 B。每个都可以构造另一个:
// A.hpp
#pragma once
class B;
class A {
B foo();
};
// A.cpp
#include <A.hpp>
#include <B.hpp>
B foo(){ return B(); }
// B.hpp
#pragma once
class A;
class B {
A foo();
};
// B.cpp
#include <B.hpp>
#include <A.hpp>
A foo(){ return A(); }
让我们介绍一种新类型:
// A_or_B.hpp
#pragma once
#include "A.hpp"
#include "B.hpp"
// or
class A;
class B;
using A_or_B = std::variant<A, B>;
让我们从 A 和 B 返回A_or_B:
// A.hpp
#pragma once
#include "A_or_B.hpp" // woops! the type for A_or_B is not resolved:
class A {
A_or_B foo();
};
哎呀呀的理由:
- 如果我们在 A_or_B.hpp 中使用 include,那么A_or_B将无法包含 A(因为标头保护) - 因此它将引用不存在的类型。
- 如果我们使用正向声明,那么A_or_B将使用不完整的类型,并且在链接阶段将不可用
和 之间不会出现循环问题,因为我们在 和 文件之间拆分了声明和实现。与类相反 - 或指令不能拆分。A
B
hpp
cpp
typedefs
using
可以做些什么来解决这个问题?
答:
2赞
jwezorek
7/19/2023
#1
您可以转发声明,然后最终将其定义为公开继承自 variant 类型的类。A_or_B
// A.hpp
#pragma once
class A_or_B;
class A {
A_or_B foo();
};
// B.hpp
#pragma once
class A_or_B;
class B {
A_or_B foo();
};
// A_or_B.hpp
#include "A.hpp"
#include "B.hpp"
class A_or_B : public std::variant<A, B> {
public:
using base = std::variant<A, B>;
using base::base;
using base::operator=;
};
0赞
chrysante
7/19/2023
#2
您可以定义为 typedef for 而不定义 和 。只有实例化类型的对象,才需要定义。A_or_B
std::variant<A, B>
A
B
A_or_B
// A.hpp
#include "A_or_B_fwd.hpp"
class A {
A_or_B foo();
};
// B.hpp
#include "A_or_B_fwd.hpp"
class B {
A_or_B foo();
};
// A_or_B_fwd.hpp
#include <variant>
class A;
class B;
using A_or_B = std::variant<A, B>;
// A_or_B.hpp
#include "A.hpp"
#include "B.hpp"
#include "A_or_B_fwd.hpp"
// A.cpp
#include "A.hpp"
#include "A_or_B.hpp"
A_or_B A::foo() { /* ... */ }
// B.cpp analogously
当正向声明比 更复杂时,使用“-fwd.hpp”样式的标头是合理的 标准库也使用 .class X;
<iosfwd>
评论
0赞
Eyal Kamitchi
7/19/2023
和 A.cpp 将具有: 1. 包括 A.hpp 2.包括 A_or_B.hpp 3。定义。右?
0赞
user7860670
7/19/2023
“你可以将 A_or_B 定义为 std::variant<A, B> 的 typedef,而无需定义 A 和 B” - 你不能 stackoverflow.com/a/57226751/7860670。
0赞
chrysante
7/19/2023
@EyalKamitchi 是,然后在各自的.cpp文件中定义 和 。A::foo()
B::foo
评论
A
B
A
B
A_or_B
A_or_B
std::variant<A, B>;
using A_or_B = std::variant<A *, B *>;
using A_or_B = ::std::unique_pt<Base>;
class State {virtual State* foo() = 0;}; class A: public State{/*override foo*/}; class B: public State{/*override foo*/}};