为什么C ++模板让我绕开不完整的类型(转发声明)? [英] Why do C++ templates let me circumvent incomplete types (forward declarations)?

查看:152
本文介绍了为什么C ++模板让我绕开不完整的类型(转发声明)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试了以下简单程序的三次迭代。这是一个高度简化的尝试,写一个容器和迭代器对类,但我遇到了不完全类型(转发声明)的问题。我发现这实际上是可能的一旦我模板化一切 - 但只有如果我实际上使用模板参数! (我意识到这一点,通过查看 Google sparsetable code 。)

I tried three iterations of the following simple program. This is a highly simplified attempt to write a container-and-iterator pair of classes, but I was running into issues with incomplete types (forward declarations). I discovered that this was in fact possible once I templatized everything - but only if I actually used the template parameter! (I realized this by looking at the Google sparsetable code.)

任何提示解释为什么第二个工作而第三个不工作? (我知道为什么第一个不工作 - 编译器需要知道容器的内存布局。)

Any hints explaining why the second works while the third doesn't? (I know why the first one doesn't work - the compiler needs to know the memory layout of the container.)

提前感谢。

// This doesn't work: invalid use of incomplete type.
#if 0
struct container;
struct iter {
  container &c;
  int *p;
  iter(container &c) : c(c), p(&c.value()) {}
};
struct container {
  int x;
  int &value() { return x; }
  iter begin() { return iter(*this); }
};
int main() {
  container c;
  c.begin();
  return 0;
}
#endif

// This *does* work.
template<typename T> struct container;
template<typename T> struct iter {
  container<T> &c;
  T *p;
  iter(container<T> &c) : c(c), p(&c.value()) {}
};
template<typename T> struct container {
  T x;
  T &value() { return x; }
  iter<T> begin() { return iter<T>(*this); }
};
int main() {
  container<int> c;
  c.begin();
  return 0;
};

// This doesn't work either.
#if 0
template<typename T> struct container;
template<typename T> struct iter {
  container<int> &c;
  int *p;
  iter(container<int> &c) : c(c), p(&c.value()) {}
};
template<typename T> struct container {
  int x;
  int &value() { return x; }
  iter<int> begin() { return iter<int>(*this); }
};
int main() {
  container<int> c;
  c.begin();
  return 0;
}
#endif


推荐答案

第一个需要定义 container ,因为您正在进行复制操作。如果你在 container 的定义后定义 iter 的构造函数,那么你就没关系了。所以:

The first requires a definition of container since you are doing a copy operation. If you define the constructor of iter after container's definition you'd be okay. So:

struct container;
struct iter {
  container &c;
  int *p;
  iter(container &c);
};

struct container {
  int x;
  int &value() { return x; }
  iter begin() { return iter(*this); }
};

iter::iter(container &c) : c(c), p(&c.value()) {}

int main() {
  container c;
  c.begin();
  return 0;
}

第二个示例工作,因为没有类,除非你实际上 main 函数。到那时,所有类型都被定义。尝试移动main之后的任何 iter 容器模板定义,您会遇到错误。

The second example works because there is no class until you actually instantiate one in your main function. By that time all types are defined. Try moving any of the iter or container templates definition after main and you'll hit an error.

第三个例子是 int 的专用化,因此出现。这应该编译,因为 iter 的模板参数不使用。你有专业化语法一点。但是,没有合适的构造函数,所以你只会得到 x 的垃圾。此外,迭代器通过指针很好地建模。传递这个的值将没有太多帮助。迭代器通常是序列所需,而不是单个对象。

The third example is a specialization for int or so it appears. This should compile because the template parameter for iter is not used. You've got the specialization syntax a bit off. However, there is no proper constructor so you'll only get garbage for x. Moreover, iterators are modeled well by pointers. Passing this's value will not be of much help. Iterators are typically required for a sequence and not an individual object. Though, there is nothing that can stop you from building one.

然后你不需要; 功能体。

And you don't need a ; after a function body.

这篇关于为什么C ++模板让我绕开不完整的类型(转发声明)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆