如果我的理解是正确的,以下是模板类之间的经典循环依赖:
template <class MyB>
struct A {
MyB *b_;
};
template <class MyA>
struct B {
MyA *a_;
};
如果我们要使用A
和B
B
来实例化A
,那么我们就不能从任何一个开始,因为我们必须写:{ {1}}(无限)。
我认为模板模板参数提供了一个解决方案。以下代码编译(使用A<B<A<B<...>>>
版本4.8.2):
gcc
我是否错过了问题的本质?
更新:我刚刚进入this帖子,提出了基本相同的解决方案。
答案 0 :(得分:2)
我会尝试设计我的代码以避免这些循环依赖。无论如何,如果有令人信服的理由提示,有几种方法可以解决这个问题:
如您所述,使用模板模板参数可以通过打破循环来解决问题
template <class MyB>
struct A {
MyB *b_;
};
template <template <class> class MyA>
struct B {
MyA<B> *a_;
};
int main() {
using MyB = B<A>;
using MyA = A<MyB>;
MyA a;
MyB b;
a.b_ = &b; b.a_ = &a;
return 0;
}
另一种解决方案可能是将您需要的类型封装到外部struct / class
中template<class Common> struct A
{
typedef typename Common::BT B;
B* b;
};
template<class Common> struct B
{
typedef typename Common::AT A;
A* a;
};
struct Common {
using AT = A<Common>;
using BT = B<Common>;
};
int main() {
A<Common> a;
B<Common> b;
return 0;
}
根据代码的其余部分,在这样的简单情况下,您可能会使用可变参数模板
template <class MyA>
struct B;
template <typename ...MyB>
struct A {
B<A<>> *b_;
};
template <>
struct A<> {};
template <class MyA>
struct B {
A<B<MyA>> *a_;
};
int main() {
using BoA = B<A<>>;
using AoBoA = A<B<A<>>>;
BoA obj1;
AoBoA obj2;
obj1.a_ = &obj2;
obj2.b_ = &obj1;
return 0;
}
最后值得注意的是,暴露一个共同的基类并使用类似CRTP的方法可能是实现这一目标的更简洁方法(你甚至可能获得清晰度和可读性的分数)