如果我的理解是正确的,以下是模板类之间的经典循环依赖:
template <class MyB>
struct A {
MyB *b_;
};
template <class MyA>
struct B {
MyA *a_;
};
如果我们想要用A来实例化A和B,那么我们就不能从任何一个开始,因为我们必须写:A< B< B< B<>>>> (无穷).
我认为模板模板参数提供了一个解决方案.以下代码编译(使用gcc版本4.8.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;
}
我错过了问题的本质吗?
更新:我刚刚进入this帖子,提出了基本相同的解决方案.
最佳答案 我会尝试设计我的代码,以避免这些循环依赖.无论如何,如果有令人信服的理由提示,有几种方法可以解决这个问题:
>如您所述,使用模板模板参数可以通过打破循环来解决问题
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;
}
>另一种解决方案可能是将您需要的类型封装到外部结构/类中
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的方法可能是实现这一目标的更简洁方法(您甚至可能获得清晰度和可读性的分数).