Suppose classes A and B. Each can construct the other:
// 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(); }
Let's introduce a new type:
// 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>;
Let's return A_or_B from A and 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();
};
Justifications for the whoops:
The cyclic problem doesn't occur between A
and B
because we split the declaration and implementation between hpp
and cpp
files. contrary to classes - typedefs
or using
directives can't be split.
what can be done to solve this?
You can define A_or_B
as a typedef for std::variant<A, B>
without defining A
and B
. Only to instantiate an object of type A_or_B
do you need the definitions.
// 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
Using "-fwd.hpp"-style headers can be reasonable when forward declarations are more complex than class X;
The standard library also does it with <iosfwd>
.