循环依赖(类对类型定义,类型定义对类),前向声明给出不明确的调用



我试图找到以下循环依赖关系的可接受的解决方案:

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?

不,这不是由于类型不完整。在使用成员之前,不会实例化成员函数定义。成员的声明将是,但类型不完整不会使声明格式不正确。更不用说,您不会以任何在不完整的情况下出现问题的方式使用该类型。

这只是名称查找规则的人工制品。您可以提供一个 using 声明来将这些f成员拉入X

template<typename T, typename U>
struct X : public Y<T>, public Y<U> {
    using Y<T>::f;
    using Y<U>::f;
};

这解决了歧义。

这与循环依赖无关,但与多重继承有关。clang错误非常明显:"错误:在不同类型的多个基类中找到成员'f'"。

一种解决方案是消除歧义,您指的是哪个f:是从Y<T>继承的还是从Y<U>继承的

z.Y<A>::f(*this);
z.Y<B>::f(*this);

我认为另一个合理的解决方案,但有点丑陋是:

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);
}

最新更新