【问题标题】:Circular reference of templates in C++, when complete types are required当需要完整类型时,C++ 中模板的循环引用
【发布时间】:2021-08-28 17:21:41
【问题描述】:

在 C# 中考虑这个例子:

class C<T> {
   
   void greetMe() { print("Hello you"); }
}

class D : C<E> {
   void useE(E e) {
      e.greetMe();
   }
}

class E : C<D> {
   void useD(D d) {
      d.greetMe();
   }
}

在 C++ 中是否可以使用模板进行等效构造?

我没有任何有用的 C++ 代码可以展示,因为我对此的兴趣纯粹是学术性的。您可以将此代码视为伪代码。

出于好奇:我正在研究急切语言处理循环引用的限制,而不是惰性语言。我记得在 C# 的类型系统中可能会发生这样的事情,我试图将其视为一种静态检查的惰性语言。我记得 C++ 的模板正好相反(但还是有点功能性?),我认为这可能是一项有趣的研究。
感谢您的宝贵时间!

Related question

【问题讨论】:

  • 我正处于添加 C# 标签的边缘。您可能想解释一下 C# 代码的作用,否则许多 C++ 程序员将无法为您提供帮助。

标签: c++ templates


【解决方案1】:

从 Not A Number 的答案扩展到相关问题,并在我认为有必要的地方嵌入 cmets:

template <class T>
class C {
public:
   void greetMe() {  }
};

class E; // forward declare E same as answer to related question
class D : public C<E> {
   void useE(E & e); // Passing by reference should be similar to the behaviour 
                     // of the C# program
                     // only declare function. Fully define later after D is complete
};

class E : public C<D> {
   void useD(D & d) { //D is already complete; we can safely define here
      d.greetMe();
   }
};

// now we can define D's implementation of useE 
void D::useE(E & e) {
   e.greetMe();
}

【讨论】:

  • 对我来说,MSVC 实际上很乐意接受 D::useE 的声明,它甚至在知道 E 的完整类型之前就按值接受 E,只要定义放在E 的定义。这个 MSVC 是否过于宽松,或者这实际上是标准允许的?
  • 是的。我应该删除该评论。我将保留它作为参考,因为它更接近 C# 原版的行为
【解决方案2】:

在定义之前你不能有一个完整的类型,因为定义是使类型完整的原因。

依赖图中可能永远不会有循环。

也就是说,D要求 E 是完整的。只有D::useE 的定义取决于该定义。因此,以下定义顺序满足所有依赖关系:DED::useE

template <class T>
struct C {
   void greetMe();
};

struct E;
struct D : C<E> {
   void useE(E e);
};

struct E : C<D> {
   void useD(D d) {
      d.greetMe();
   }
};

void D::useE(E e) {
    e.greetMe();
};

【讨论】:

    猜你喜欢
    • 2021-08-28
    • 2019-06-21
    • 1970-01-01
    • 2013-12-10
    • 1970-01-01
    • 1970-01-01
    • 2011-12-15
    • 1970-01-01
    相关资源
    最近更新 更多