#include 模板递归
#include recursion with template
我有类似的问题 Why can templates only be implemented in the header file? (and there Correct way of structuring CMake based project with Template class) 但包含递归。
代码:
A.h
#pragma once
#include "B.h"
struct A
{
B b;
void doThingA() {}
};
B.h
#pragma once
struct A;
struct B
{
A *a;
template<typename T>
void doThingB();
};
#include "A.h"
template<typename T>
void B::doThingB()
{
a->doThingA();
}
main.cpp
#include "A.h"
int main() {}
错误:
In file included from A.h:2,
from main.cpp:1:
B.h: In member function 'void B::doThingB()':
B.h:16:6: warning: invalid use of incomplete type 'struct A'
16 | a->doThingA();
| ^~
B.h:2:8: note: forward declaration of 'struct A'
2 | struct A;
| ^
B.h
包含来自 A.h
但 B.h
中模板函数实现所需的 A.h
不包含。由于模板的原因,我也无法对 .cpp
进行实施。
可以通过使用模板的显式实例化来解决,但我想知道另一种解决方案。
当您拥有紧密耦合的类型时,最简单的解决方案是将它们放在一个 header 文件中。
#pragma once
// forward declaration of A
struct A;
// declare B, since A needs it
struct B
{
A *a;
template<typename T>
void doThingB();
};
// now we can declare A
struct A
{
B b;
void doThingA() {}
};
// and finally, implement the parts of B that need A
// and need to be in the header
template<typename T>
void B::doThingB()
{
a->doThingA();
}
如果你还想要一个B.h
,那么它可以是一行:
#include "A.h"
如果您想将 A
/B
拆分为您自己组织的多个 header,一个简单的解决方案是添加 compile-time 检查以确保文件不直接包括在内。
// A.h
#pragma once
#define A_IMPL
#include "B_impl.h"
#undef A_IMPL
// B.h
#pragma once
#ifndef A_IMPL
#error "B_impl.h can't be included directly; use A.h"
#endif
struct A;
struct B
{
A *a;
template<typename T>
void doThingB();
};
#include "A_impl.h"
template<typename T>
void B::doThingB()
{
a->doThingA();
}
// A_impl.h
#pragma once
#ifndef A_IMPL
#error "A_impl.h can't be included directly; use A.h"
#endif
struct A
{
B b;
void doThingA() {}
};
如果您希望更多的 header 直接使用 impl 文件,您可以使 #ifdef
检查更复杂,但是 public 界面仍然很幸福地不知道。
基于 Stephen 的解决方案,我提出了该架构:
A.h
#pragma once
#define A_H
#include "B.h"
struct A
{
B b;
void doThingA() {}
};
#include "B_impl.h"
B.h
#pragma once
struct A;
struct B
{
A *a;
template <typename T>
void doThingB();
};
#ifndef A_H
#include "B_impl.h"
#endif
B_impl.h
#pragma once
#include "A.h"
template <typename T>
void B::doThingB()
{
a->doThingA();
}
main.cpp
#include "A.h"
int main() {}
所以我可以分别包含 A.h
和 B.h
,而且它看起来更干净。
我有类似的问题 Why can templates only be implemented in the header file? (and there Correct way of structuring CMake based project with Template class) 但包含递归。
代码:
A.h
#pragma once
#include "B.h"
struct A
{
B b;
void doThingA() {}
};
B.h
#pragma once
struct A;
struct B
{
A *a;
template<typename T>
void doThingB();
};
#include "A.h"
template<typename T>
void B::doThingB()
{
a->doThingA();
}
main.cpp
#include "A.h"
int main() {}
错误:
In file included from A.h:2,
from main.cpp:1:
B.h: In member function 'void B::doThingB()':
B.h:16:6: warning: invalid use of incomplete type 'struct A'
16 | a->doThingA();
| ^~
B.h:2:8: note: forward declaration of 'struct A'
2 | struct A;
| ^
B.h
包含来自 A.h
但 B.h
中模板函数实现所需的 A.h
不包含。由于模板的原因,我也无法对 .cpp
进行实施。
可以通过使用模板的显式实例化来解决,但我想知道另一种解决方案。
当您拥有紧密耦合的类型时,最简单的解决方案是将它们放在一个 header 文件中。
#pragma once
// forward declaration of A
struct A;
// declare B, since A needs it
struct B
{
A *a;
template<typename T>
void doThingB();
};
// now we can declare A
struct A
{
B b;
void doThingA() {}
};
// and finally, implement the parts of B that need A
// and need to be in the header
template<typename T>
void B::doThingB()
{
a->doThingA();
}
如果你还想要一个B.h
,那么它可以是一行:
#include "A.h"
如果您想将 A
/B
拆分为您自己组织的多个 header,一个简单的解决方案是添加 compile-time 检查以确保文件不直接包括在内。
// A.h
#pragma once
#define A_IMPL
#include "B_impl.h"
#undef A_IMPL
// B.h
#pragma once
#ifndef A_IMPL
#error "B_impl.h can't be included directly; use A.h"
#endif
struct A;
struct B
{
A *a;
template<typename T>
void doThingB();
};
#include "A_impl.h"
template<typename T>
void B::doThingB()
{
a->doThingA();
}
// A_impl.h
#pragma once
#ifndef A_IMPL
#error "A_impl.h can't be included directly; use A.h"
#endif
struct A
{
B b;
void doThingA() {}
};
如果您希望更多的 header 直接使用 impl 文件,您可以使 #ifdef
检查更复杂,但是 public 界面仍然很幸福地不知道。
基于 Stephen 的解决方案,我提出了该架构:
A.h
#pragma once
#define A_H
#include "B.h"
struct A
{
B b;
void doThingA() {}
};
#include "B_impl.h"
B.h
#pragma once
struct A;
struct B
{
A *a;
template <typename T>
void doThingB();
};
#ifndef A_H
#include "B_impl.h"
#endif
B_impl.h
#pragma once
#include "A.h"
template <typename T>
void B::doThingB()
{
a->doThingA();
}
main.cpp
#include "A.h"
int main() {}
所以我可以分别包含 A.h
和 B.h
,而且它看起来更干净。