C ++ 템플릿이 왜 불완전한 유형 (선언)을 우회 할 수있는 이유는 무엇입니까?

StackOverflow https://stackoverflow.com/questions/620378

문제

다음 간단한 프로그램의 세 가지 반복을 시도했습니다. 이것은 컨테이너 및 정화기 클래스 쌍을 작성하려는 매우 단순화 된 시도이지만 불완전한 유형 (전진 선언)으로 문제가 발생했습니다. 나는 이것이 모든 것을 템플릿 한 후에는 실제로 가능하다는 것을 발견했지만 실제로 템플릿 매개 변수를 사용한 경우에만 가능합니다! (나는 이것을 보면서 이것을 깨달았다 Google Sparsetable 코드.)

두 번째로 작동하지 않는 이유를 설명하는 힌트는 무엇입니까? (첫 번째 것이 작동하지 않는 이유를 알고 있습니다. 컴파일러는 컨테이너의 메모리 레이아웃을 알아야합니다.)

미리 감사드립니다.

// 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 사본 작업을하고 있기 때문에. 생성자를 정의하는 경우 iter ~ 후에 container당신은 괜찮을 것입니다. 그래서:

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 기능. 그때까지 모든 유형이 정의됩니다. 어떤 것을 움직이십시오 iter 또는 container 메인 이후 정의가 템플릿하면 오류가 발생합니다.

세 번째 예는 전문화입니다 int 또는 그것이 나타납니다. 템플릿 매개 변수가 있으므로 컴파일해야합니다 iter 사용되지 않습니다. 당신은 전문화 구문을 조금 꺼 냈습니다. 그러나 적절한 생성자가 없으므로 쓰레기만을 얻을 수 있습니다. x. 또한 반복자는 포인터로 잘 모델링됩니다. 통과 this의 가치는 큰 도움이되지 않습니다. 반복자는 일반적으로 개별 객체가 아닌 시퀀스에 필요합니다. 그러나, 당신이 하나를 짓는 것을 막을 수있는 것은 없습니다.

그리고 당신은 필요하지 않습니다 ; 기능 본문 후.

다른 팁

컨테이너 정의 후 iter :: iter ()를 정의하여 템플릿 없이이 작업을 수행 할 수 있습니다.

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

템플릿 버전은 템플릿을 인스턴스화 할 때 두 클래스 모두 완전히 정의되므로 작동합니다.

첫 번째 경우, 클래스가 정의되기 전에 컨테이너 클래스의 멤버 기능에 액세스하려고하므로 작동하지 않습니다.

두 번째 경우, 템플릿은 처음으로 특정 유형과 함께 사용될 때 인스턴스화됩니다. 이 시점에서 컨테이너 클래스는 주로 정의되었으므로 컴파일됩니다.

세 번째 경우에는 원형 기준이 있습니다. 컨테이너는 반복을 사용하고 ITER은 컨테이너를 사용하므로 작동 할 수 없습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top