我试图找到一个可接受的解决方案来解决以下循环依赖:
template<typename T>
struct Y {
void f(T&) {}
};
template<typename T, typename U>
struct X : public Y<T>, public Y<U> {};
struct A;
struct B;
typedef X<A,B> Z;
struct A {
void g(Z& z) {
z.f(*this);
}
};
struct B {
void g(Z& z) {
z.f(*this);
}
};
int main(int argc, char** argv) {
Z z;
A a;
B b;
a.g(z);
b.g(z);
}
代码Z取决于A和B,A / B取决于Z.A / B无法转换为模板类定义。当我转发声明A和B时(如图所示)然后我得到一个不明智的调用,大概是因为typedef用不完整的类型实例化X?
当然,我可以简单地将X定义为以下内容,一切正常:
struct A;
struct B;
struct X {
void f(A&) {}
void f(B&) {}
};
typedef X Z;
struct A {
void g(Z& z) {
z.f(*this);
}
};
struct B {
void g(Z& z) {
z.f(*this);
}
};
int main(int argc, char** argv) {
Z z;
A a;
B b;
a.g(z);
b.g(z);
}
...但是当X是模板时如何将Z定义为typedef?
答案 0 :(得分:5)
不,这不是因为类型不完整。在使用该成员之前,不会实例化成员函数定义。成员的声明将,但是不完整的类型不会使声明格式不正确。更不用说,你不会以任何方式使用该类型,因为它不完整。
这只是名称查找规则的一个人工制品。您可以提供使用声明,将f
成员拉入X
:
template<typename T, typename U>
struct X : public Y<T>, public Y<U> {
using Y<T>::f;
using Y<U>::f;
};
这解决了歧义。
答案 1 :(得分:2)
这与循环依赖关系无关,但具有多重继承。铿锵的错误很明显:&#34;错误:会员&#39; f&#39;在多个不同类型的基类中找到&#34;。
一种解决方案是消除歧义f
您的意思:是继承自Y<T>
还是继承自Y<U>
的人:
z.Y<A>::f(*this);
z.Y<B>::f(*this);
答案 2 :(得分:1)
我认为另一个解决方案是合理的,但有点难看的是:
template<typename T>
struct Y {
void f(T&) {}
};
template<typename T, typename U>
struct X : public Y<T>, public Y<U> {
template<typename V>
void f(V& v) {
this->Y<V>::f(v);
}
};
struct A;
struct B;
typedef X<A,B> Z;
struct A {
void g(Z& z) {
z.f(*this);
}
};
struct B {
void g(Z& z) {
z.f(*this);
}
};
int main(int argc, char** argv) {
Z z;
A a;
B b;
a.g(z);
b.g(z);
}